[{"content":"วันก่อนครับ เพื่อนร่วมงานผมบอกว่า PR ผมอ่านยากชิบหาย\nแม่งจริง เพราะว่าฟีเจอร์ที่ผมเปิด PR ไปนั้น ถ้าเป็นสมัยก่อนผมน่าจะใช้เวลาทั้งอาทิตย์แต่รอบนี้คือผมใช้เวลาแค่บ่ายวันเดียวกับ Agent ก็เสร็จ ผมยัดทุกอย่างลง PR ด้วยความภาคภูมิใจกับความสามารถในการคุม Agent ของผมทั้ง Spec ทั้ง Implementation เป็นร้อยๆ บรรทัด\nพอส่งให้รีวิว เพื่อนร่วมงานผมบอกว่า มันลำบากมากในการทำความเข้าใจโค้ด หรือไล่โค้ดอย่างเป็นระบบ เพราะว่ามันจะมี Spec หรือคำอธิบายที่ Agent เติมแต่งขึ้นมานอกจากโค้ดมาทำให้ไขว้เขว มาขัด Flow ในการทำความเข้าใจอยู่เรื่อยๆ\nสิ่งที่พังจริงๆ หลังจากผ่านมาซักพักใหญ่ ผมว่าผมเริ่มเข้าใจละว่ามันเกิดอะไรขึ้น และผมสามารถพูดได้เต็มปากว่า\nต้นทุนในการผลิตโค้ดมันลดลงจนแทบไม่เหลือ แต่ต้นทุนในการทำความเข้าใจมันไม่ได้ถูกลงเลย\nทุกๆ Practice ที่เราถูกสอนกันมา ถูกสร้างมาสำหรับโลกที่ “การเขียนโปรแกรม” คือส่วนที่แพงที่สุด ถูกสร้างจากสมมติฐานว่าโค้ดเกิดขึ้นได้เพราะผ่านการคิดมาแล้ว ในอดีตการคิดนั้นถูกส่งต่อผ่าน Code Review ที่ซึ่งคนในทีมจะได้ถ่ายทอดการเรียนรู้ให้กัน แต่พอปริมาณโค้ดที่ผลิตมีมากขึ้นเกินกว่าที่คนๆ หนึ่งจะรับไหว สิ่งนั้นแหละที่ทำให้เกิดช่องว่างทางการเรียนรู้ และมันขยายใหญ่ขึ้นมากเรื่อยๆ\nสิ่งที่ผมลองทำ พอผมรู้ตัวว่า PR ผมมันปนกันระหว่าง Spec กับ Implementation การทดลองแรกผมเลยลองแยก Spec ออกมาเป็น PR หนึ่ง ตามด้วย Implementation ออกมาเป็นอีก PR หนึ่งที่ Stack อยู่บน PR แรกอีกที ถ้าเพื่อนร่วมงานผมไม่สนว่า ผมสั่ง Agent ผ่าน Spec ยังไงบ้าง เค้าก็แค่ Skip PR แรกไปดูโค้ดเองได้เลย\nซึ่งเหมือนจะเวิร์ค แต่ก็สร้างปัญหาใหม่ตามมาทันทีเพราะ Stack PRs ต้อง Merge ตามลำดับ ทำให้ผมต้องจัดการ Dependency ในการ Merge เพิ่มมาอีกต่อหนึ่งด้วย และก็ต้องอธิบายเพิ่มด้วยว่า PR อันนี้ต้องเข้าก่อนอันนี้นะ แทนที่จะแค่โฟกัสกับสิ่งที่สำคัญที่สุดจริงๆ ซึ่งก็คือ Implementation นั้นแหละ\nแต่ในความซับซ้อน มันก็มีข้อดีอยู่นะ เพราะหลังจากทำอย่างนี้ได้ซักพัก ผมก็เริ่มรู้ตัวว่าสิ่งที่ควรแก้จริงๆ ไม่ใช่ Workflow ในการ Merge แต่คือความเข้าใจว่าเรามี Spec เอาไว้ทำไม\nผมใช้ Spec เพื่อที่จะสร้าง Implementation เวอร์ชั่นแรก แล้วหลังจากนั้นค่อย Refactor ตามมา ตัว Spec จะถูกใช้เป็น Reference ของ Logic แต่จะไม่เคยถูกอัพเดทตามมาเลย พอถึงจุดที่ผม Refactor จนพอใจแล้ว ถึงแม้ Business Logic (What) จะยังเหมือนเดิมอยู่แต่วิธีการที่ Implement (How) มันต่างจากที่อธิบายไว้ใน Spec ตอนแรกไปแล้วครับ\nงั้นก็อัพเดท Spec หลัง Refactor ด้วยสิ ผมลองละครับและมันไม่เวิร์ค เพราะ Spec ถูกเขียนออกมา “ก่อนที่เราจะรู้อะไร หลายๆ อย่าง”\nเราไม่มีทางที่จะออกแบบ Software ได้อย่างสมบูรณ์แบบก่อนที่จะ Implement ไม่ว่าเราจะพยายามมาแค่ไหนก็ตาม เพราะว่าความรู้บางอย่างจะเกิดขึ้นได้ในระหว่างที่เรากำลังสร้างมันออกมาเท่านั้น หลายครั้งที่เรากำลังเขียนโปรแกรมอยู่ก็นึกวิธีการที่ดีกว่าได้ออกและ Agent ไม่สามารถทำสิ่งนี้ได้ ไม่ใช่เพราะว่ามันจำ Context ไม่ได้เก่ง แต่เพราะมันไม่ได้เห็นภาพใหญ่ของงานที่คุณกำลังทำอยู่ และ “คุณไม่เคยบอกมัน เพราะคุณไม่รู้ตัวด้วยซ้ำว่าต้องบอก”\nเพราะฉะนั้นเนี่ยในมุมมองผม Spec มันได้ทำงานตอบโจทย์ของมันแล้วตั้งแต่เราสั่งมัน Implement จนเสร็จเป็นเวอร์ชั่นแรก เวอร์ชั่นที่เราจะได้เล่น ได้แกะ ได้แงะดูว่าเป็นอย่างที่เราต้องการมั้ย และทุกอย่างที่เราเรียนรู้หลังจากจุดๆ นี้มันเกิดขึ้นกับเรา และการที่เราต้องกลับไปถ่ายทอดความรู้นี้กลับไปที่ Spec ทำให้เราต้องดูแล knowledge ถึง 2 ที่ซึ่งก็จะผิดทันที ถ้าเรา Refactor ต่อไป\nพอถึงจุดนี้เนี่ยผมโยน Spec ทิ้งละครับ สิ่งที่เหลืออยู่คือ Business logic ที่ถูก Implement ลงไปอยู่ในโค้ดเรียบร้อยแล้วและได้ถูก Refactor มาถึงจุดที่ผมสามารถอธิบายทุกส่วนของมันได้\nผมไม่ได้บอกว่าวิธีนี้ดีที่สุดนะ แต่อย่างน้อยโค้ดมันก็เล็กลง ถึงจุดที่ผมสามารถรับผิดชอบมันได้และไม่ต้องให้ใครไปอ่าน Spec ถึงจะเข้าใจมันครับ\nแต่ถ้าสังเกตุดีๆ สุดท้าย ผมก็ไม่ได้แก้ปัญหาคอขวดของ Code Review นะ แต่สิ่งที่ผมทำจริงๆ คือ ทำงานหนักขึ้นก่อนจะส่งโค้ดให้เพื่อนร่วมงาน Review เพื่อที่จะมั่นใจได้ว่า โค้ดที่ต้อง Review จะถูกจัดสรรให้มีขนาดที่เล็กพอที่คนๆ หนึ่งจะเข้าใจได้โดยที่ไม่ใช้พลังเยอะไป\nนั่นแหละครับคือสิ่งที่ผมอยากจะสื่อ เราต้องคิดถึงคนที่ดูแลโค้ดด้วยกันด้วย ถ้าเราไม่ทำมันก่อนที่จะเปิด PR มันคือการที่เราบังคับให้เพื่อนร่วมงานทำสิ่งนั้นแทนเรากับโค้ดที่เค้าไม่คุ้นเคยด้วยซ้ำ\nอีกครึ่งหนึ่งของปัญหา ในอีกสถานการณ์หนึ่ง ผมกำลัง Pair กับเพื่อนร่วมงานผมอยู่กับฟีเจอร์ที่เค้าสร้างด้วย Agent ตัวฟีเจอร์ถูกสร้างมาอย่างละเอียดครอบคลุมทุก edge case ที่ควรจะเป็นไม่มีอะไรขาด\nผมเลยเริ่มถามคำถาม\nอันนี้เราต้องการจริง ๆ เหรอ? เคสนี้มันจะเกิดขึ้นจริงไหม? ทำให้ง่ายกว่านี้ได้ไหม? ใช้ X แทน Y ได้หรือเปล่า? สังเกตุว่ามันไม่ใช่คำถามที่ยากเลย แต่พอได้ดูโค้ดที่เกิดขึ้น ผมคิดอะไรขึ้นได้อย่างนึงกับวิธีการที่เราอ่านโค้ดกันในตอนนี้\nทุกครั้งที่มีโค้ดถูกผลิตมากขึ้นเกินกว่าจุดที่เราสามารถจะทำความเข้าใจได้ เราจะหยุด Evaluate มันและจะเริ่มปรับโหมดสมองเป็น accept / reject ตัว Agent อาจจะมาปิด gap ของ requirements ได้ทุกๆ branch condition ดูก็รู้ว่าถูกต้อง ในใจเราก็คิดว่า เยี่ยม ดีครับผม เหมาะสมครับ Agent ไม่มีการหยุดคิดเพราะว่าตอนนี้ Input ที่เราต้องตัดสินใจมันมากกว่าเกินกว่าที่สมองเราจะรับได้แล้ว\nมันเลยกลับมาที่หลักการง่ายๆ 2 อย่างที่ผมยึดเป็นหลักเวลาทำงานกับโค้ดที่ถูก Agent สร้างขึ้นมา\nเขียนขึ้นมาทำไมนะ ยึดกับสิ่งที่เรารู้เป็นหลัก หลายครั้งที่เราไม่จำเป็นต้องเขียน Edge case ให้ครอบคลุมขนาดนั้นก็ได้ ปล่อยให้มันระเบิดไปแล้วค่อยแก้ถ้ามันเกิดขึ้นจริง สำคัญคือ เราไม่จำเป็นต้องทำถูกตั้งแต่ครั้งแรก แต่พูดอย่างงี้ก็สุ่มเสี่ยง เอาเป็นว่า ถ้าไม่ใช่ระบบที่สำคัญอย่างการเงิน หรือข้อมูลอาจจะกู้กลับมาไม่ได้ ปล่อยให้มันแตกเลยครับ เขียนให้ง่ายกว่านี้ได้มั้ย การเขียนโค้ดให้มันน้อยลง แปลว่าสิ่งที่เราต้องทำความเข้าใจก็น้อยลงไปด้วย และทำให้เรามีพื้นที่ในสมองเพิ่มมากขึ้นที่จะคิดไปไกลกว่า ของที่เราเห็นอยู่ตรงหน้า หลายครั้งที่เราบอกไม่ได้หรอกว่า Abstraction ที่เราเขียนมามันดีหรือยัง แต่ถ้าเราสั่งให้มันลองทำให้สั้นลง ง่ายลงซักร้อยครั้ง คุณก็จะเริ่มรู้ตัวเองว่าชอบโค้ดแบบไหน บ่ายวันนั้นเราน่าจะตัดโค้ดกันไปเยอะระดับหนึ่ง และพอถึงจุดที่พอใจแล้วทั้งผมกับเพื่อนร่วมงานก็เข้าใจทั้งตัวฟีเจอร์และเหตุผลว่าทำไมต้องเขียนแบบนั้นกันทั้งคู่\nแต่ว่า Model มันเก่งขึ้นทุกวันนะ ผมยอมรับ เพราะมันก็เก่งขึ้นทุกวันจริงๆ วันนึงโค้ดที่มันผลิตออกมาก็จะดีขึ้น แล้วบล็อกนี้ก็จะไม่ต่างอะไรกับคน gen y กำลังบ่นคน gen z แต่เอาจริงๆ มันก็ถูกครึ่งนึง หลายเรื่องที่เราต้องคิดเยอะๆ เวลาเขียนโค้ดเดี๋ยวนี้เราก็คิดน้อยลงแล้วอย่างพวก Syntax หรือ Semantic อันนี้ Agent มันเก่งจริง\nและถึงแม้ Model มันจะเก่งขึ้นทุกปี แต่มันก็ไม่ได้ทำให้ ตัวเรา เก่งขึ้นตามมันไปด้วย มันอาจจะผลิตโค้ดได้เก่งมากกว่าเรา แต่อย่าลืมว่ามันก็หยุดทำงานได้เหมือนกันหรือใกล้ตัวหน่อยคือ token หมด พอถึงจุดที่เราต้องอยู่กับตัวเองคำถามคือ เรายังทำงานได้อยู่มั้ย\nนั่นแหละครับคือราคาที่เราต้องจ่ายจริงๆ ถ้ายังอยู่กับ Agent เพราะฉะนั้นถามตัวเองดังๆ ตลอดครับว่าเรายังอยู่ได้โดยไม่มีมันมั้ย\nสรุป ตอนที่ผมยังเป็น Junior อยู่ Lead ผมเคยสอนไว้ว่า แม้แต่ ช่องว่างระหว่างบรรทัดก็สามารถเล่าเรื่องราวได้ เพราะว่าสิ่งที่เราเขียน เราเขียนเพื่อให้คนอื่นมาอ่านต่อ แล้วพอมามองในยุคนี้ คำสอนนี้ยิ่งสำคัญมากขึ้นไปอีก เพราะว่าคนอื่นนั้น ไม่ใช่แค่เพื่อนร่วมงาน แต่อาจจะเป็นเราในอีก 6 เดือนข้างหน้า หรือแม้แต่ Agent ที่เราสั่งเพื่อที่จะให้มันแก้บางอย่าง\nสุดท้ายแล้ว Spec จะ Obsolete ตัว Context จะเต็ม Session หมดอายุ แต่อะไรก็ตามที่เราเรียนรู้ระหว่างที่ปรับโค้ดจะอยู่กับเราตลอดไปและจะถูกส่งต่อไปยังคนที่มาอ่านต่อถ้าเค้าถามเกี่ยวกับโค้ดนั้น\nโค้ดที่ถูกสร้างด้วย Agent จะยังอยู่ต่อไปครับ แต่เราสามารถอยู่ร่วมกับมันได้ถามตัวเองดังๆ เขียนมันขึ้นมาทำไมนะ หรือ เขียนให้มันง่ายกว่านี้ได้มั้ย เป็นคนที่คอยคุมมันแทนที่จะให้มันคุมเรา เพราะมนุษย์เราไม่สมบูรณ์แบบครับ เรามีข้อจำกัด เราทำพลาด แต่นั่นก็ทำให้เราได้เรียนรู้ด้วย และสิ่งที่เราเรียนรู้นี่แหละที่ไปได้ไกลเกินกว่า Token limit และส่งต่อไปกับคนอื่นได้ด้วย สวัสดีครับ\n","permalink":"https://yothinix-com.pages.dev/living-with-agent-gen-code/","summary":"\u003cp\u003eวันก่อนครับ เพื่อนร่วมงานผมบอกว่า PR ผมอ่านยากชิบหาย\u003c/p\u003e\n\u003cp\u003eแม่งจริง เพราะว่าฟีเจอร์ที่ผมเปิด PR ไปนั้น ถ้าเป็นสมัยก่อนผมน่าจะใช้เวลาทั้งอาทิตย์แต่รอบนี้คือผมใช้เวลาแค่บ่ายวันเดียวกับ Agent ก็เสร็จ ผมยัดทุกอย่างลง PR ด้วยความภาคภูมิใจกับความสามารถในการคุม Agent ของผมทั้ง Spec ทั้ง Implementation เป็นร้อยๆ บรรทัด\u003c/p\u003e\n\u003cp\u003eพอส่งให้รีวิว เพื่อนร่วมงานผมบอกว่า มันลำบากมากในการทำความเข้าใจโค้ด หรือไล่โค้ดอย่างเป็นระบบ เพราะว่ามันจะมี Spec หรือคำอธิบายที่ Agent เติมแต่งขึ้นมานอกจากโค้ดมาทำให้ไขว้เขว มาขัด Flow ในการทำความเข้าใจอยู่เรื่อยๆ\u003c/p\u003e\n\u003ch2 id=\"สงทพงจรงๆ\"\u003eสิ่งที่พังจริงๆ\u003c/h2\u003e\n\u003cp\u003eหลังจากผ่านมาซักพักใหญ่ ผมว่าผมเริ่มเข้าใจละว่ามันเกิดอะไรขึ้น และผมสามารถพูดได้เต็มปากว่า\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eต้นทุนในการผลิตโค้ดมันลดลงจนแทบไม่เหลือ แต่ต้นทุนในการทำความเข้าใจมันไม่ได้ถูกลงเลย\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eทุกๆ Practice ที่เราถูกสอนกันมา ถูกสร้างมาสำหรับโลกที่ “การเขียนโปรแกรม” คือส่วนที่แพงที่สุด ถูกสร้างจากสมมติฐานว่าโค้ดเกิดขึ้นได้เพราะผ่านการคิดมาแล้ว ในอดีตการคิดนั้นถูกส่งต่อผ่าน Code Review ที่ซึ่งคนในทีมจะได้ถ่ายทอดการเรียนรู้ให้กัน แต่พอปริมาณโค้ดที่ผลิตมีมากขึ้นเกินกว่าที่คนๆ หนึ่งจะรับไหว สิ่งนั้นแหละที่ทำให้เกิดช่องว่างทางการเรียนรู้ และมันขยายใหญ่ขึ้นมากเรื่อยๆ\u003c/p\u003e\n\u003ch2 id=\"สงทผมลองทำ\"\u003eสิ่งที่ผมลองทำ\u003c/h2\u003e\n\u003cp\u003eพอผมรู้ตัวว่า PR ผมมันปนกันระหว่าง Spec กับ Implementation การทดลองแรกผมเลยลองแยก Spec ออกมาเป็น PR หนึ่ง ตามด้วย Implementation ออกมาเป็นอีก PR หนึ่งที่ Stack อยู่บน PR แรกอีกที ถ้าเพื่อนร่วมงานผมไม่สนว่า ผมสั่ง Agent ผ่าน Spec ยังไงบ้าง เค้าก็แค่ Skip PR แรกไปดูโค้ดเองได้เลย\u003c/p\u003e","title":"โค้ดที่เราไม่ได้เขียน เขียนขึ้นมาทำไมนะ"},{"content":" We can solve any problem by introducing an extra level of indirection\nDeveloper หลายๆ คนน่าจะคุ้นเคยกับ Theorem ข้างบนมาบ้างจาก Fundamental theorem of Software Engineering (FTSE) ซึ่งหลายๆ คนก็น่าจะเห็นด้วย เพราะมันฟังดูเข้าใจง่ายมาก แค่เพิ่ม Interface หรือ Wrapper ขึ้นมาแค่นั้น แต่จริงๆ แล้วนี่เป็นความเข้าใจคลาดเคลื่อนไปมาก เพราะส่วนใหญ่ Developer เราจะสับสนระหว่าง Abstraction กับ Indirection ถ้าไม่ระวังให้ดี และไอความสับสนนี่แหละที่ทำให้ code เราเปลี่ยนจาก clean ๆ กลายเป็น Spaghetti ได้เลย\nAbstraction vs Indirection ความเข้าใจผิดมากที่สุดของเรื่องนี้คือ การที่คิดว่าสองสิ่งนี้มันเป็นสิ่งเดียวกัน เรามาลองดูนิยามมันคร่าวๆ ของสองสิ่งนี้กันครับ\nAbstraction is about \u0026ldquo;What\u0026rdquo; ตัว Abstraction ทำหน้าที่เป็นสัญญา ที่ซ่อนความซับซ้อน (complexity) ของการทำงานหนึ่งๆ ทุกครั้งที่เราใช้ Interface เป็นการบอกว่า \u0026ldquo;เราไม่สนนะว่าข้างในมันจะทำงานยังไง ตราบใดที่มันยังทำงานได้ตามกรอบที่เราวางไว้\u0026rdquo; เรียกว่าเป็นมุมมองแบบ Passive ก็ได้ Indirection is about \u0026ldquo;Where\u0026rdquo; ในส่วนของ Indirection สามารถอธิบายได้ง่ายๆ ว่าเป็นป้ายบอกทางมากกว่า โดยทำหน้าที่เป็นตัวกลาง (middleman) คอยบอกว่าให้เลี้ยวซ้าย เลี้ยวขวานะ ตาม Action ที่ได้รับมา หรือมองในอีกมุมของเป็นการตอบรับแบบ Active ครับ\nอีกจุดหนึ่งที่ทำให้ Indirection แตกต่างจาก Abstraction อย่างชัดเจนคือการต้องมี Registry ครับ ยกตัวอย่างกลับไปที่ Analogy ของป้ายบอกทางก็ได้ ถ้าเราอยู่ที่ 3 แยก มันต้องมีคนมาเขียนป้ายบอกว่า ถ้าเลี้ยวซ้ายไปไหน ถ้าเลี้ยวขวา แล้วจะไปถึงไหน นั่นแหละครับการ Registry ซึ่งนี่เป็นหลักการพื้นฐานไม่ต่างจากการที่เรามี DNS Resolver (เชื่อมระหว่าง Domain -\u0026gt; IP) หรือ built-in Python method อย่าง getattr() (เชื่อม String -\u0026gt; class method) ทุกอย่างมีราคา ย้อนกลับไปที่ FTSE ข้างบนครับ จริงๆ แล้วมันไม่จบแค่นั้น มันยังมีครึ่งหลังที่คนไม่ค่อยรู้อยู่ กล่าวไว้โดย David Wheeler ว่า\n\u0026hellip;except for the problem of too many levels of indirection\nลองจินตนาการภาพตามนะครับ ทุกครั้งที่เราเพิ่มของเข้ามาใน Indirection ตัว Register ที่ทำงานอยู่จะทำงานหนักขึ้นเรื่อยๆ ครับ และเราจะเริ่ม Debug ยากขึ้นเรื่อยๆ เพราะมันไม่ใช่การเรียก function ตรงไปตรงมา แต่เราต้องไปที่ Register ก่อนว่า action นี้หมายถึง function ไหน แล้วค่อยไล่ไปจากตรงนั้น แค่คิดก็ปวดหัวแล้วใช่มั้ยครับ กลับมาที่ Analogy ป้ายบอกทางครับ ตัวอย่างที่ชัดเจนมากก็คือ ห้าแยกลาดพร้าวนี่แหละครับ\nเพราะฉะนั้นแล้วเนี่ย กฏข้อสำคัญที่เราควรจะพึงระลึกไว้เสมอคือ เราควรพึ่ง Indirection ก็ต่อเมื่อ Complexity ที่เกิดขึ้นนั้นน้อยกว่า การเรียก Action มันตรงๆ ครับ\nเราจะเป็นคนควบคุมมันหรือจะเป็นคนที่ถูกมันควบคุม ครั้งหน้าถ้าเราเขียนโค้ด ลองถามตัวเองสั้นๆ ครับว่า Logic ที่เรากำลัง Implement อยู่เนี่ย มันจะถูกใช้เฉพาะงานส่วนนี้โดยเฉพาะ หรือว่ามันสามารถยกระดับไปเป็นระบบที่ใช้กับงานที่หลากหลายได้ ซึ่งการเลือกใช้แนวคิด Indirection คือการเลือกที่จะ ไม่ตอบคำถามนี้ แต่เป็นการเลือกที่จะหาทางที่จะหาคำตอบให้กับคำถามนี้ได้ในอนาคต ครับ\n","permalink":"https://yothinix-com.pages.dev/the-deception-of-indirection/","summary":"\u003cblockquote\u003e\n\u003cp\u003eWe can solve any problem by introducing an extra level of indirection\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eDeveloper หลายๆ คนน่าจะคุ้นเคยกับ Theorem ข้างบนมาบ้างจาก Fundamental theorem of Software Engineering (FTSE) ซึ่งหลายๆ คนก็น่าจะเห็นด้วย เพราะมันฟังดูเข้าใจง่ายมาก แค่เพิ่ม Interface หรือ Wrapper ขึ้นมาแค่นั้น แต่จริงๆ แล้วนี่เป็นความเข้าใจคลาดเคลื่อนไปมาก เพราะส่วนใหญ่ Developer เราจะสับสนระหว่าง Abstraction กับ Indirection ถ้าไม่ระวังให้ดี และไอความสับสนนี่แหละที่ทำให้ code เราเปลี่ยนจาก clean ๆ กลายเป็น Spaghetti ได้เลย\u003c/p\u003e\n\u003ch2 id=\"abstraction-vs-indirection\"\u003eAbstraction vs Indirection\u003c/h2\u003e\n\u003cp\u003eความเข้าใจผิดมากที่สุดของเรื่องนี้คือ การที่คิดว่าสองสิ่งนี้มันเป็นสิ่งเดียวกัน เรามาลองดูนิยามมันคร่าวๆ ของสองสิ่งนี้กันครับ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eAbstraction is about \u0026ldquo;What\u0026rdquo;\u003c/strong\u003e ตัว Abstraction ทำหน้าที่เป็นสัญญา ที่ซ่อนความซับซ้อน (complexity) ของการทำงานหนึ่งๆ ทุกครั้งที่เราใช้ Interface เป็นการบอกว่า \u0026ldquo;เราไม่สนนะว่าข้างในมันจะทำงานยังไง ตราบใดที่มันยังทำงานได้ตามกรอบที่เราวางไว้\u0026rdquo; เรียกว่าเป็นมุมมองแบบ Passive ก็ได้\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIndirection is about \u0026ldquo;Where\u0026rdquo;\u003c/strong\u003e ในส่วนของ Indirection สามารถอธิบายได้ง่ายๆ ว่าเป็นป้ายบอกทางมากกว่า โดยทำหน้าที่เป็นตัวกลาง (middleman) คอยบอกว่าให้เลี้ยวซ้าย เลี้ยวขวานะ ตาม Action ที่ได้รับมา หรือมองในอีกมุมของเป็นการตอบรับแบบ Active ครับ\u003cbr\u003e\nอีกจุดหนึ่งที่ทำให้ Indirection แตกต่างจาก Abstraction อย่างชัดเจนคือการต้องมี Registry ครับ ยกตัวอย่างกลับไปที่ Analogy ของป้ายบอกทางก็ได้ ถ้าเราอยู่ที่ 3 แยก มันต้องมีคนมาเขียนป้ายบอกว่า ถ้าเลี้ยวซ้ายไปไหน ถ้าเลี้ยวขวา แล้วจะไปถึงไหน นั่นแหละครับการ Registry ซึ่งนี่เป็นหลักการพื้นฐานไม่ต่างจากการที่เรามี DNS Resolver (เชื่อมระหว่าง Domain -\u0026gt; IP) หรือ built-in Python method อย่าง \u003ccode\u003egetattr()\u003c/code\u003e (เชื่อม String -\u0026gt; class method)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"ทกอยางมราคา\"\u003eทุกอย่างมีราคา\u003c/h2\u003e\n\u003cp\u003eย้อนกลับไปที่ FTSE ข้างบนครับ จริงๆ แล้วมันไม่จบแค่นั้น มันยังมีครึ่งหลังที่คนไม่ค่อยรู้อยู่ กล่าวไว้โดย David Wheeler ว่า\u003c/p\u003e","title":"The Deception of Indirection"},{"content":"วันที่ 29 ธันวาที่ผ่านมาผมเพิ่งเรียนจบ DeepLearning.AI Data Engineering Professional Certificate มาครับ เป็น Coursera Specialization ตัวที่ 2 ในชีวิต หลังจากได้ตัวแรก Developing Application with Google Cloud เมื่อหลายปีมาแล้ว\nแต่เอาจริงๆ ผมก็ไม่ได้ตั้งใจว่าจะเก็บเป็น Specialization อะไรหรอกครับ จุดเริ่มต้นของเรื่องราวนี้คือ ผมรู้จัก Joe Reis จากหนังสือ Fundamentals of Data Engineering มาก่อนหน้านี้แล้วกับ Subscribe newsletter ของเค้าด้วย พอช่วงประมาณเดือนสิงหาถ้าผมจำไม่ผิดนะ อาจารย์ Andrew Ng เปิดตัวเว็บ deeplearning.ai ขึ้นมา แล้วผมก็เหลือบไปเห็นคอร์ส Data Engineering ในนั้นมาว่าจะเปิดตัวเร็วๆ นี้ แถมสอนโดย Joe Reis อีก ผมรอจนถึงเวลาเปิดตัวแล้วเค้าก็เลื่อนเปิด จนช่วงปลายๆ เดือนกันยาถึงเปิด ผมก็เริ่มเรียนตั้งแต่วันแรกเลย\nอาจารย์ Joe\nCourse Format ตัวคอร์สนี้จั่วหัวว่า Specialization สำหรับคนที่ไม่เคยเรียน Coursera ตัว Specialization หมายความว่าจะเป็นชุดคอร์สที่จะประกอบไปด้วยคอร์สย่อยๆ หลายคอร์ส ถ้าเรียนจบครบทุกตัว นอกจากเราจะได้ Certificate ของแต่ละคอร์สแล้ว เราจะได้ตัว Cert Specialization เพิ่มอีกด้วยครับ ซึ่งโดยตัว Specialization เองสามารถมองเป็น Learning Path ได้ด้วย เพราะจากประสบการณ์ผมแต่ละคอร์สที่เรียงมาให้จะ support ความรู้ให้เราต่อยอดใน Course ถัดๆ ไปได้ครับ\nซึ่งใน Specialization นี้จะแบ่งเป็น Course ย่อย 4 คอร์สคือ\nในแต่ละคอร์สย่อยจะใช้เวลาประมาณ 3-4 สัปดาห์แล้วแต่คอร์ส (แต่ส่วนใหญ่ 4 ยกเว้นคอร์ส 3) โดยในแต่ละสัปดาห์นั้น จะแบ่งเป็น Video Lecture ประมาณ 1.30 - 2 hrs ตามมาด้วย Lab Assignments 2-4 ตัว อันนี้แล้วแต่สัปดาห์เลย แล้วปิดท้ายด้วย Weekly Quiz 10 ข้อทุกสัปดาห์ โดยตัว Lab Assignment บางตัวกับ Weekly Quiz จะเป็นตัวตัด Grade ว่าเราจะเรียนผ่านหรือไม่ผ่านในตอนจบแต่ละคอร์สโดยต้องผ่าน 80% ขึ้นไปถึงจะผ่านในหัวข้อนั้นๆ\nด้วยความที่ตัวคอร์สวางตารางเป็นสัปดาห์ให้ทำให้แต่ละอาทิตย์จะมี Deadline ของแต่ละ Assignment, Quiz ที่ต้องเรียนให้จบภายในอาทิตย์นั้น แต่จริงๆ จะเกินก็ได้ แต่ส่วนตัวผมแนะนำว่าให้พยายามเรียนของแต่ละอาทิตย์ให้จบภายในอาทิตย์นั้น เพราะพอมันสะสมไปเรื่อยๆ มันเหนื่อยมากครับ (แค่พยายามเรียนให้จบแต่ละอาทิตย์ก็เหนื่อยละ)\nสุดท้ายครับ ถ้าจะได้ Certificate กับทำ Lab ต้อง Subscribe Coursera ด้วยซึ่งอยู่ที่ $49 ต่อเดือนครับ ตั้งแต่เริ่มจนจบคอร์สใช้เวลาประมาณ 3 เดือนหรือ 15 สัปดาห์ ผมแนะนำมากๆ ว่าให้จัดสรรเวลาเรียนกับชีวิตดีๆ ครับเพราะมันกินเวลาประมาณ 3-6 ชม. ต่อสัปดาห์เลย แต่ไม่แนะนำให้เรียนอัดรวดเดียวครับ เพราะเนื้อหามันเยอะจริงๆ แล้วอาจจะไม่ค่อยได้อะไรกลับไป\nWho should taking this course ส่วนตัวผมที่เป็น Role Data Engineer มาเกือบๆ 3 ปีกับประสบการณ์ Software Engineer รวม 10 ปี ผมขอแบ่งคำแนะนำหัวข้อนี้ออกเป็น 2 กลุ่มใหญ่ๆ ละกันครับ\nBeginner / Freshly Graduated สำหรับมือใหม่ Specialization นี้ผมมองว่าเก็บภาพกว้างได้หมด ตั้งแต่ต้นน้ำ ไปจนถึงปลายน้ำในกลุ่มงาน Data Engineering ครับไล่ตั้งแต่เก็บ Business objective แปลงมาเป็น Technical Requirements มาจนถึงการเลือกใช้เทคโนโลยีแต่ละส่วน ไปจนถึงรูปแบบ data model ที่ส่งมอบตัวข้อมูลเพื่อไปใช้ประโยชน์ต่อไปครับ\nแต่ด้วยความที่มันไม่ใช่ Lecture นั่งฟังอย่างเดียวแต่มี Lab ด้วยทำให้ได้มีโอกาสได้ลองใช้เทคโนโลยีหลายๆ อย่างเพื่อประกอบเป็น data pipeline ทั้ง Batch, Streaming เพื่อเพิ่มความมั่นใจและความพร้อมในการจะไปทำงานต่อจริงๆ ด้วย\nLab Course นี้สนุกมากครับ\nExperienced / Seasoned Engineer ในส่วนของคนที่มือเปื้อนมาบ้าง ผมว่ามันเป็นการเติมเต็มส่วนที่ขาดมากกว่า เพราะในงานจริงๆ แต่ละบริษัทอาจจะเป็นได้ทั้ง Green field, Brown field แตกต่างกันไป ทำให้โอกาสที่เราจะได้ลอง Tooling / Pattern / Practice ต่างๆ อาจจะไม่ได้ครบทั้งหมดเช่น งานส่วนใหญ่อาจจะทำแต่ Batch processing pipeline ไม่ได้ทำ Streaming pipeline บ่อยๆ หรืออย่างเช่น การทำ Data modeling ให้แต่ละ data user ก็อาจจะตกเป็นงานของ Role อื่นอย่าง Analytic Engineer หรือ Data Analyst แทน ตัวคอร์สนี้เลยเข้ามาเติมเต็มในส่วนที่ขาดหลายๆ ส่วนให้เราได้กลับมารื้อฟื้นปัดฝุ่นความรู้เรา ว่าของพวกนี้ควรจะออกแบบยังไง ส่งมอบยังไงครับ\nต่อไปเป็นรายละเอียดแต่ละคอร์สจากประสบการณ์ผมเองครับ\nCourse 1: Introduction to Data Engineering สำหรับคอร์สแรกนี้พอมามองย้อนกลับไป ก็ยังคงใช้คำเดิมว่ามันคือความ Overview และ Definition ครับ เพราะคอร์สแรกจะพาเราไปรู้จักนิยามต่างๆ ของคำที่เกี่ยวข้องใน Data Engineering Field แล้วต่อด้วยพระเอกอย่าง Data Engineering Life Cycle ครับ\nตัว Life Cycle พยายามจะวางกรอบงานและเครื่องมือให้อยู่ในรูปแบบเดียวกัน แต่ก็ยังไม่ละองค์ประกอบที่จำเป็นอื่นๆ ในการทำงานเพราะ Data Engineering ก็เป็น kind of Software Engineering แบบนึง ในส่วนของ Undercurrent เลยเป็นส่วนที่ อาจจะไม่อยู่ในรูป flow หลัก แต่เป็นองค์ประกอบที่ขาดไม่ได้ที่เติมเต็มให้ flow หลักทำงานได้ดี\nData Engineering Lifecycle\nด้วยความที่คอร์สนี้มีความ Partner กับ AWS ด้วย ส่วนหนึ่งของคอร์สแรกคือการ Intro ให้รู้จัก AWS ด้วยครับ ซึ่งพาให้เราไปรู้จักกับ Well-architected Framework ที่เป็นเซ็ตของคำถามให้เราคิดเวลาเราจะ implement อะไรบน Cloud แต่ที่เสริมขึ้นมาด้วยความเป็นคอร์ส Data Engineering คือการแนะนำให้เรารู้จักสิ่งที่เรียกว่า Principles of Good Data Architecture ครับ ส่วนตัวผมชอบ Section นี้มาก เพราะจากประสบการณ์มันคือเรื่องสำคัญแต่ไม่ใช่ Hard work แต่เป็น Soft work ที่ต้องทำคู่ไปด้วยเพื่อจะทำให้งานหลักออกมาดี\nPrinciples of Good Data Architecture\nในส่วนสุดท้ายของคอร์ส 1 จะพาเราไปแมพความรู้ของ Data Engineering Life Cycle กับวิธีคิดของ Data Engineer ออกมาเป็น Requirements ที่เราจะเอาไปทำงานต่อครับ ซึ่งดีมากๆ ใครยังรับงาน Data Engineer แต่ไม่รู้จะเก็บ requirements ออกมาให้เป็นรูป เป็นร่างยังไง ผมแนะนำในส่วนของสัปดาห์ที่ 4 คอร์สนี้เลย\nThink like a Data Engineer\nCourse 2: Source Systems, Data Ingestion, and Pipelines พอเรารู้จักภาพกว้างในคอร์สแรกแล้ว คอร์สสองตัวนี้จะพาเราไปลงลึกใน 2 ก้อนแรกของ Data Engineering Life Cycle คือ Data Generation, Ingestion แล้วเสริมด้วย Undercurrent ทั้ง Security, DataOps, Orchestration ครับ\nส่วนของ Source System ก็คือ Data ต้นน้ำที่เราต้องไปทำงานด้วยในคอร์สนี้พาไปรู้จักทั้งในแกน Structured, Semi-Structured, Unstructured Data และลงลึกไปแต่ละประเภทอีกทั้ง Database (Relational, NoSQL) ที่เล่าไปจนถึง ACID Compliance หรือประเภทอย่าง Object storage, REST API, Logs เรื่อยมาจนถึง Streaming System\nBatch Ingestion Patterns\nส่วนของ Data Integration นี่จะลงใน Pattern ที่จะอยู่ในกรอบของ frequency ไล่ตั้งแต่ Batch, Micro-batch ไปจนถึง Streaming หรือจะมองในมิติ ETL vs ELT ว่ามีข้อดี ข้อเสียต่างกันยังไง แล้วด้วยความที่คอร์สนี้พื้นฐานอยู่บน AWS เราจะได้ใช้ components อย่าง AWS Glue Job, AWS Kinesis ในการทำแล็บ Data Integration ด้วยครับ\nส่วนของ Undercurrent ในมุมของ Security คือพาไปรู้จัก IAM Security กับ AWS Networking ว่าจะ control ยังไงรวมไปถึงหัด debugging ปัญหา ACL ใน AWS ด้วย ส่วนของ DataOps ในส่วนของทฤษฏีจะแบ่งเป็น 3 pillars: Automation, Observability \u0026amp; Monitoring, Incident Response\nDataOps Pillars\nโดย Automation จะเน้นไปที่การใช้ Terraform มาช่วย Provision component ต่างๆ ใน AWS แบบ Infrastructure as a Code (IaaS) และ Observability \u0026amp; Monitoring จะเน้นไปที่การใช้ Great Expectation มาช่วยทำ Data Quality กับ AWS Cloudwatch ในการทำ Monitoring ครับ\nในส่วนสุดท้ายของคอร์สนี้คือ Data Orchestration / Pipelines จะสรุปง่ายๆ ว่าไปเรียน Airflow ก็ได้ครับ แต่จะลงไปตั้งแต่ Cron, DAGs, และพาไปรู้จักองค์ประกอบของ Airflow server เรื่อยไปจนถึง API ของ Airflow เช่น Operators, XCom, Variables หรือ TaskFlow API\nManaged Apache Airflow on AWS\nพอมามองย้อนกลับไป Course 2 นี่มันเนื้อหาเยอะจนร้องขอชีวิตจริงๆ แหะ\nCourse 3: Data Storage and Queries ถ้าคอร์ส 1 กับคอร์ส 2 คืองานที่เราจะได้ทำจริงๆ เป็นการวางองค์ประกอบให้แต่ะละส่วนประสานงานกัน Course 3 นี่ผมเปรียบว่าเป็นรากฐานที่ทำให้ 1+2 ทำงานได้ครับ โดยในคอร์สนี้จะเน้นไปที่การทำงานและการเลือกใช้ Storage ของ data ที่เราดึงมาจาก Source Systems แล้วครับ\nData Storage System \u0026amp; Abstraction\nโดยเนื้อหานี่ไล่ตั้งแต่ Physical storage อย่าง Magnetic Disk, SSD, RAM, CPU Cache ขึ้นมาเป็น Logical storage อย่าง File Hierarchy, Block Storage, Object Storage มาจนชั้น Application storage อย่าง Key-value in-memory, Rows, Columnar, Graph, Vector\nพอ components แน่นแล้วก็ยกระดับขึ้นมาเป็น Abstraction อย่าง Data Warehouse, Data Lake, Data Lakehouse ซึ่งไม่ใช่แค่ Abstraction ที่พูดถึง แต่ยังลงไปที่ tooling ที่ช่วยให้มันเกิดขึ้นได้อย่าง MPP (Redshift), Open table format (Iceberg) ด้วยครับ\nData Lakehouse on AWS\nและแน่นอนว่าเราจะพูดถึง Application Storage โดยไม่พูดถึง Queries ไม่ได้ครับ ใน ส่วนนี้นั้นเรียกได้ว่าเขียน Queries จนต้องร้องขอชีวิตตั้งแต่ basic อย่าง select, from, where, join, aggregation เรื่อยไปจน advance statement อย่าง SQL Functions, CTEs, condition expression, sub-queries, และ Sliding windows ครับ นอกจากนี้ยังพาเราไปรู้จักกับเทคนิคการ Optimize queries บน database อย่างการ Index บน RDBMS หรือ Sort key บน Columnar DB และปิดท้ายด้วยการเขียน Queries บน Streaming System โดยอาศัย Window pattern หลายๆ แบบครับ\nCourse 4: Data Modeling, Transformation, and Serving พอผ่านคอร์ส 1-3 มาเราจะเริ่มมีไอเดีย, เครื่องมือและเทคนิคแล้วว่าจะพา Data จากจุด A → B ยังไง ในส่วนของคอร์ส 4 จะเป็นเรื่องของการวาง Model ของ Data เพื่อให้ Downstream system หรือ Data User เอา Data ไปใช้งานได้ง่ายและเกิดประโยชน์สูงสุดครับ\nพาร์ท Data Modeling นี่ส่วนหนึ่งเหมือนกลับไปเรียนวิชา Database สมัยมหาลัยมาก ไล่ตั้งแต่ Normalization (1NF → 3NF), Star Schema แต่ก็เพิ่งรู้ว่าในโลก Data Warehouse เค้าแบ่งกันเป็น 2 ค่ายคือ ค่าย Inmon ที่เน้น Join ทำ 3NF กับค่าย Kimball ที่เน้นการวาง Star Schema ซึ่งในคอร์สนี้ไล่ให้เห็นแต่ละแบบเลยว่ามีข้อดี ข้อเสียยังไงบ้าง นอกจากนี้ยังมีค่ายที่ 3 อย่าง Data Vault ที่แบ่ง Model เป็น Hub, Link, Satellite ด้วย รวมไปถึงเทคนิคที่ง่ายที่สุดอย่าง One Big Table (OBT) ด้วย ซึ่งเราจะได้ฝึกการวาง Data modeling เหล่านี้ผ่านเครื่องมืออย่าง dbt ด้วยครับ\nData Modeling Approaches\nในส่วนของ Data Modeling ยังมีอีกส่วนคือการเตรียม Data ของเราเพื่อสนับสนุนการทำ Feature Engineering ใน ML Project Lifecycle Framework ครับ ทั้งในส่วนที่เป็น Numerical data อย่าง Handling missing, Scaling Numerical, Encoding หรือส่วนของ Text data อย่าง Cleaning, Normalization, Tokenization, Remove stop words, Lemmatization ซึ่งในแล็บได้เขียน Pandas กับ Scikit-learn เตรียม data อย่างเมามันครับ\nพอเข้าเนื้อหา Data Transformation จะเป็น Transformation ในส่วนของปลายน้ำมากกว่าตอนที่เราทำ Data Ingestion ครับ โดยจะพูดถึงเทคนิคอย่าง Truncate \u0026amp; Reload, Capture update, Capture delete มีแวะมาเล่าเรื่อง Hadoop ให้เราเข้าใจก่อนจะยกระดับไปถึง Spark แล้วเน้นไปที่การเลือกใช้ระหว่าง Spark UDF, DataFrame API, Spark SQL และ Spark Streaming\nSpark DataFrame API\nในส่วนสุดท้ายของคอร์ส Serving จะย้ำเราถึงรูปแบบของการส่งมอบครับว่าจะทำยังไงถึงจะส่งมอบ Data แต่ยัง Compliance กับ Data Management อยู่ ซึ่งแต่ละ Use case ทั้ง Analytics, ML ก็จะมีความต้องการรวมถึงรูปแบบที่แตกต่างกัน เลยต้องเกิดสิ่งที่เรียกว่า Semantic Layer ขึ้นมาขั้นอีกชั้นนึง ซึ่งตัว Semantic Layer นี้จะ Implement ในรูปแบบของ View / Materialize View / Dataset ใน Superset แตกต่างกันไปแต่ละ Use case ครับ\nSemantic layer\nตัวคอร์ส 4 จะจบด้วย Capstone project ครับ เป็นเหมือนการทวนเราอีกรอบให้เราใช้ความรู้ตั้งแต่ต้นน้ำการเก็บ requirements เลือกเทคโนโลยีทำ data pipeline โดย Ingest และทำ Data Quality check ผ่าน component บน AWS อย่าง Glue, transforms เป็น Star Schema ผ่าน dbt แล้ว Serving ด้วย Superset โดยทั้งหมดถูก Orchestrate ผ่าน Airflow\nCapstone Lab\nจบแล้วครับ ขอบคุณทุกคนที่อ่านจนจบ ถ้าเขียนไม่ค่อยรู้เรื่องกราบขออภัยเพราะเนื้อหามันเยอะจริงๆ อยากบอกว่าเป็น 3 เดือนที่ได้ความรู้เยอะมาก ล้นมาก แล้วผมมั่นใจมาก ว่าที่ผมเขียนไว้ข้างบนก็ยังเก็บมาไม่หมดกับความรู้ที่ผมได้มาในคอร์สนี้ครับ ถ้าใครตัดสินใจเรียนแล้วขอให้เรียนให้จบครับ มันคุ้มมากกับเวลาที่เสียไป แล้วถ้าใครเรียนจบแล้วเหมือนกัน ขอแสดงความยินดีด้วยคนครับ ถึงใครจะไม่รู้ แต่รู้ไว้ว่าผมคนนึงที่เข้าใจความตั้งใจและเหนื่อยยากในการผ่าน 3 เดือนนี้มาได้ สวัสดีครับ\nจบครบ 4 Course ได้ Certificate Specialization มาเท่ๆ อีกใบ\n","permalink":"https://yothinix-com.pages.dev/deeplearning-ai-data-engineering/","summary":"\u003cp\u003eวันที่ 29 ธันวาที่ผ่านมาผมเพิ่งเรียนจบ \u003ca href=\"https://www.coursera.org/professional-certificates/data-engineering\"\u003e\u003cstrong\u003eDeepLearning.AI Data Engineering Professional Certificate\u003c/strong\u003e\u003c/a\u003e มาครับ เป็น Coursera Specialization ตัวที่ 2 ในชีวิต หลังจากได้ตัวแรก \u003ca href=\"https://www.coursera.org/specializations/developing-apps-gcp\"\u003e\u003cem\u003eDeveloping Application with Google Cloud\u003c/em\u003e\u003c/a\u003e เมื่อหลายปีมาแล้ว\u003c/p\u003e\n\u003cp\u003eแต่เอาจริงๆ ผมก็ไม่ได้ตั้งใจว่าจะเก็บเป็น Specialization อะไรหรอกครับ จุดเริ่มต้นของเรื่องราวนี้คือ ผมรู้จัก Joe Reis จากหนังสือ \u003ca href=\"https://www.amazon.com/Fundamentals-Data-Engineering-Robust-Systems/dp/1098108302\"\u003e\u003cem\u003eFundamentals of Data Engineering\u003c/em\u003e\u003c/a\u003e มาก่อนหน้านี้แล้วกับ Subscribe \u003ca href=\"https://joereis.substack.com/\"\u003e\u003cem\u003enewsletter\u003c/em\u003e\u003c/a\u003e ของเค้าด้วย พอช่วงประมาณเดือนสิงหาถ้าผมจำไม่ผิดนะ อาจารย์ Andrew Ng เปิดตัวเว็บ \u003ca href=\"https://www.deeplearning.ai/\"\u003e\u003cem\u003edeeplearning.ai\u003c/em\u003e\u003c/a\u003e ขึ้นมา แล้วผมก็เหลือบไปเห็นคอร์ส Data Engineering ในนั้นมาว่าจะเปิดตัวเร็วๆ นี้ แถมสอนโดย Joe Reis อีก ผมรอจนถึงเวลาเปิดตัวแล้วเค้าก็เลื่อนเปิด จนช่วงปลายๆ เดือนกันยาถึงเปิด ผมก็เริ่มเรียนตั้งแต่วันแรกเลย\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/deeplearning-ai-data-engineering/Screenshot-2567-12-31-at-11.59.41_hu_ff3bd1488f0be7c9.webp\"\n       srcset=\"/deeplearning-ai-data-engineering/Screenshot-2567-12-31-at-11.59.41_hu_da0c139be77e5dc1.webp 480w, /deeplearning-ai-data-engineering/Screenshot-2567-12-31-at-11.59.41_hu_24c67a4c3fc7e13.webp 960w, /deeplearning-ai-data-engineering/Screenshot-2567-12-31-at-11.59.41_hu_ff3bd1488f0be7c9.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"744\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eอาจารย์ Joe\u003c/em\u003e\u003c/p\u003e\n\u003ch2 id=\"course-format\"\u003eCourse Format\u003c/h2\u003e\n\u003cp\u003eตัวคอร์สนี้จั่วหัวว่า Specialization สำหรับคนที่ไม่เคยเรียน Coursera ตัว Specialization หมายความว่าจะเป็นชุดคอร์สที่จะประกอบไปด้วยคอร์สย่อยๆ หลายคอร์ส ถ้าเรียนจบครบทุกตัว นอกจากเราจะได้ Certificate ของแต่ละคอร์สแล้ว เราจะได้ตัว Cert Specialization เพิ่มอีกด้วยครับ ซึ่งโดยตัว Specialization เองสามารถมองเป็น Learning Path ได้ด้วย เพราะจากประสบการณ์ผมแต่ละคอร์สที่เรียงมาให้จะ support ความรู้ให้เราต่อยอดใน Course ถัดๆ ไปได้ครับ\u003c/p\u003e","title":"Review: DeepLearning.AI Data Engineering Professional Certificate"},{"content":"ขอย้อนความก่อน ถ้าใครสนใจแค่เรื่องการตรวจ VO2 Max จะข้ามส่วนนี้ไปเลยก็ได้ครับ ต้องย้อนไปว่าปีนี้ผมกลับมาวิ่งแล้วครับ หลังจากหยุดวิ่งจริงจังไปหลายปีมากๆ แล้วผมจะมีความคาใจอยู่นานตั้งแต่สมัยวิ่งไปถึง Half Marathon แล้วว่าผมไม่สามารถวิ่งยาวๆ จนจบได้เลย แต่เป็นวิ่งสลับเดินมาตลอด ถึงแม้จะพยายามเก็บระยะ จะพยายามซ้อมตามตารางแล้วก็เถอะ\nจนกลับมาวิ่งรอบนี้ผมตั้งเป้าหมายง่ายมาก (น่าจะง่ายแหละ) คือขอแค่วิ่งยาวๆ จบ ไม่ต้องหยุดเดินตามระยะที่ต้องการได้ก็พอ ทีนี้พอเข้าโปรแกรมซ้อมกับนาฬิกา สิ่งที่ค้นพบหลังจากผ่านไปไม่กี่สัปดาห์คือ ผมกลับมา Loop เดิมคือยังวิ่งตามโปรแกรมซ้อมจนจบไม่ได้ Pace ลั่น จนหมดแรงแล้วก็เดินอีกแล้ว จนเริ่มเรียนรู้ที่จะคุม Pace ให้เป็นซึ่งเป็นจุดเปลี่ยนมาก เพราะผมเริ่มวิ่งได้ไกล ได้นานขึ้นเรื่อยๆ แล้วพัฒนาการมันเพิ่มขึ้นแบบรู้สึกได้\nแต่พอผ่านไปได้ประมาณ 3/4 ของโปรแกรมมันก็ถึงจุดที่ผมกลับมาคาใจอีก ผมเริ่มที่จะรู้สึกว่า Hit-the-wall เหมือนมีกำแพงที่ข้ามไปไม่ได้คือไป Pace ที่ต้องการไม่ได้ซักที อีกจุดที่คาใจคือ เริ่มรู้สึกว่านาฬิกามันโชว์ Heart Rate Zone แปลกๆ เวลาวิ่งคือไป Zone 3-4 ทั้งๆ ที่ผมรู้สึกว่าเอะ มันก็ยังไม่เหนื่อยนี่หว่า แต่บางวัน Zone 4 ก็เหนื่อยมากๆ เลยรู้สึกว่ามันมีอะไรผิดปกติละ\nจังหวะนั้นคือเริ่มมองหาตัวช่วยละ เลยไปเจอใน The Running Channel ว่ามันมีตรวจอะไรแบบนี้ด้วย หลังจากนั้นก็เริ่มหาข้อมูลเลยมาเจอของไทยมีหลายที่เลย แต่ผมเจอของ Health Performance Team กับคุณหมอแอร์ที่เป็นนักกีฬาด้วย เลยตัดสินใจนัดเลย\nการนัดหมายกับการเตรียมตัว อย่างแรกคือการนัดหมายคือทักไปในเพจ Health Performance Team เลยครับ แล้วเดี๋ยวมีเจ้าหน้าที่ติดต่อกลับมา จริงๆ มีหลายโปรแกรมตรวจให้เลือกด้วย แต่ผมเลือกเป็น VO2 Max เลยเพื่อมาตอบคำถามที่คาใจตัวเองอยู่\nหลังจากนัดหมายเสร็จก่อนวันตรวจจริงมีเจ้าหน้าที่โทรมายืนยันนัดหมายอีกที แล้วก็บอกให้เตรียมตัวเช่น งดออกกำลังกายหนัก นอนอย่างน้อย 8 ชม. งดอาหารอย่างน้อย 4 ชม. แล้วก็เตรียมชุดกีฬากับรองเท้ากีฬามาเปลี่ยนด้วย\nการทดสอบ พอถึงวันจริงเจอคุณหมอแอร์ตามเวลาครับ หมอจะซักประวัติก่อนต่อจากที่พยาบาลถามเบื้องต้นมาก่อนหน้านี้ ถามไปถึงค่าที่ตรวจสุขภาพมาก่อนหน้านี้ก็เลยเอาผลแล็บให้หมอดูด้วยเลยไปถึงโรคประจำตัวถึงรุ่นบรรพบุรุษเลย เรียกได้ว่าถามละเอียดมากๆ\nถามประวัติเสร็จก็ถึงเวลาทดสอบ อย่างแรกคือใส่หน้ากากที่จะต่อไปกับถังอากาศก่อน ซึ่งที่เคยดูๆ รีวิวจากหลายๆ ที่มาจะชอบบอกว่าหน้ากากจะรัดแน่นมาก แต่ผมว่าถึงแค่ระดับกระชับไม่ถึงกับอึดอัดครับ แล้วยังหายใจได้ ตรงหัวมันจะมีเหมือนพัดลมคอยพัดอากาศเข้ามาให้เราอีกที\nอย่างที่สองคือติดเหมือนตัววัดคลื่นหัวใจ ซึ่งติดไว้หลายจุดหลายมุมมาก 10 กว่าจุด รวมถึงสายวัด Heart rate ที่หน้าอกด้วย ณ จุดนี้คือตรงหน้าท้องไปจนถึงหน้าอก เต็มไปด้วยอุปกรณ์พะรุงพะรังเต็มไปหมด ถึงจุดนี้คือเริ่มกังวลละว่าจะวิ่งได้ปะวะ ของห้อยเยอะขนาดนี้ พอทุกอย่างเรียบร้อยก็ถึงขึ้นสายพานครับ ซึ่งคุณนักวิทยาศาสตร์การกีฬาก็มาอธิบายวิธีการทดสอบเพิ่ม ว่าสายพานจะเร็วขึ้นเรื่อยๆ แล้วให้เรายกมือบอกระดับความเหนื่อยของเรา ที่เพิ่มขึ้นเรื่อยๆ หลังจากนั้นก็ถึงเวลาทดสอบจริง\nขั้นแรกของการทดสอบคือ ยืนนิ่งๆ 90 วิครับ หลังจากนั้นลู่วิ่งจะเริ่มเคลื่อนตั้งแต่ช้าๆ แล้วเร็วขึ้นเรื่อยๆ ระหว่างนั้นคุณนักวิทย์ก็จะถามเรื่อยๆ ว่าระดับความเหนื่อยถึงไหนแล้วเช่น ถ้าถึงระดับ 5 แล้วยกมือบอกครับ ซึ่งช่วงแรกๆ มันก็ช้ามากๆ แต่ความเข้มข้นมันเริ่มตอนที่มันเร็วพอที่เราจะต้องก้าววิ่งนี่แหละครับ จังหวะนั้นคือค่อยๆ ไล่ไปเรื่อยๆ 6 7 8 จากที่เคยหายใจแค่จมูกก็เริ่มใช้ปากช่วย จากตอนแรกที่รู้สึกว่าวิ่งได้เรื่อยๆ เริ่มวิ่งเซไปทางขวาของลู่เรื่อยๆ จนทุกคนต้องคอยบอกให้กลับมาทางซ้าย พอถึงระดับ 8 ใกล้ๆ 9 ตอนนั้นคือหายใจถี่มากๆ หายใจดังมากๆ ได้ยินคุณหมอถาม กต ว่าปกติผมหายใจแรงแบบนี้มั้ย เป็นหอบหืดมั้ย แต่ตอนนั้นคือหายใจจะไม่ทันละ เลยถึงจุดที่พอละก็ยกมือบอก คุณนักวิทย์ฯ ก็ช่วยนับถอยหลังให้ หลังจากนั้นลู่วิ่งก็ค่อยๆ ลดความเร็วลงเรื่อยๆ จนหยุด ใช้เวลาประมาณ 15 นาทีครับตั้งแต่เริ่มยืนจนถึงหยุด\nผลการทดสอบ หลังจากหายเหนื่อยถอดอุปกรณ์เรียบร้อยแล้ว คุณนักวิทย์ก็จะมาสรุปผลการทดสอบให้เลย ในส่วนนี้ขอแบ่งเป็น 4 Section ย่อยๆ\nPerformance Analysis ส่วนนี้คุณนักวิทย์ของเราพาเราแปลผลจากกราฟ 9 Plots ซึ่งเยอะมาก แต่ช่วยให้เราเห็น Trending แต่ละ Aspect เลย ซึ่งสุดท้ายแล้วสรุปหลักๆ ออกมาเป็น 3 เรื่อง\nVO2 Max — ตัวนี้ผลออกมาวันนี้ต่ำกว่าเกณฑ์คนทั่วไปที่อายุเท่ากันอยู่ แต่ข้อสังเกตุอีกอย่างของผมเองคือ ค่ามันต่ำกว่าค่าที่อ่านได้จากนาฬิกาแหะ Oxygen Pulse — ค่าบีบตัวของหัวใจสูงสุดวันนี้ก็ยังต่ำกว่าเกณฑ์คนทั่วไปที่อายุเท่ากัน เหมือนกัน แต่คุณนักวิทย์อธิบายเพิ่มว่า ถ้าดูในเชิง Performance ยังยอดเยี่ยมอยู่เพราะ Heart Rate กับการบีบของหัวใจทำงานต่อเนื่องสัมพันธ์กันไปอยู่ตั้งแต่ต้นจนจบการทดสอบ Lung Function — ประสิทธิภาพของปอดต่ำกว่าเกณฑ์คนทั่วไปที่อายุเท่ากันอยู่ แต่ช่วงความเหนื่อยสูงสุดยังมีช่วงที่ปอดยังไม่ได้ใช้งานอยู่เยอะระดับนึงเลย แปลว่ายังมีช่องว่างที่พัฒนาต่อไปได้อีก Exercise Program Based on VO2 Max test ส่วนนี้คุณนักวิทย์ของเราจะช่วงวางโปรแกรมออกกำลังกายให้จากค่าหัวใจกับความเร็วที่ได้จากการทดสอบโดยแบ่งเป็น\nSession 1: Base Aerobic Session 2: Anaerobic threshold (Tempo) Interval (1000m x 4) Session 3: HIIT at 100% VO2 Max (ลงคอร์ทหรือ Treadmill) Session 4: Fat Burn Zone ซึ่งแต่ละ Session เราจะได้ทั้งตัวเลขความเร็วที่เป็น Pace (min/km) และความเร็วบน Treadmill (km/hr) ให้เราเอาไปใช้ต่อได้ครับ\nGoal Race Pace อย่างที่เกริ่นไปตอนแรกว่า Goal ผมตอนนี้คือ จบ 10K ได้แบบวิ่งยาวๆ ไม่เดินเลย คุณนักวิทย์เลยช่วยคำนวนให้ได้ค่า Pace ที่เหมาะสมให้ ซึ่งเป็นจุดที่ใช้พลังงานจาก ไขมัน 70% และจากคาร์บ 30% อันนี้หลังจากได้ผลเอามาเทียบกับค่า VDOT กับ Race Estimator ที่เคยคำนวนได้คือใกล้เคียงมากๆ (อาจจะช้ากว่านิดหน่อยหลักหน่วยวินาที)\nHeart Rate Zone ค่านี้คือค่าที่ผมมาตามหาครับ ซึ่งก็แบ่งเป็น 5 Zone อย่างที่เราเข้าใจเลย\nZone 5 (Top) Zone 4 (Development) Zone 3 (Intensive Endurance) Zone 2 (Extensive Endurance) Zone 1 (Compensation) ซึ่งคุณนักวิทย์เราแนะนำว่า ของวันนี้ที่ทดสอบอยู่ใน Control environment เป็นห้องแอร์ ถ้าออกไปวิ่งข้างนอกอากาศร้อน ให้บวกไปประมาณ 7 bpm ทุก Zone กำลังดี ซึ่งผมเอามาเทียบกับ Zone ที่นาฬิกาคำนวนให้ Based On %Max. HR นี่คือคนละเรื่องกันเลย จะมีส่วนที่เป็น %HRR ที่ดูใกล้เคียงไปทางเดียวกันหน่อย แต่ก็ยังไม่ตรงกันอยู่ดี\nค่าผลการทดสอบทั้งหมดที่ได้จากการเดินสายผ่านจะถูกส่งมาให้เราใน email อีกทีครับ ถ้าจำไม่ได้ตอนที่ฟังหลังจากวิ่งมาเหนื่อยๆ ก็ไม่เป็นไร หลังจากนั้นระหว่างที่รอคุณหมอแอร์แปลผลอีกคน เป็นช่วงที่เราแว็บไปอาบน้ำ เปลี่ยนชุดได้ครับ\nในส่วนของคุณหมอแอร์สรุปผลให้ ผมขอแบ่งเป็น 3 Section ย่อยๆ ครับ\nRunning Form Analysis ในส่วนนี้คุณหมอจะวิเคราะห์ท่าวิ่งในช่วงที่เราวิ่งอยู่ที่ระดับ Threshold ครับ ซึ่งหมอก็ถ่ายคลิปไว้ทั้งด้านหลังและด้านข้าง เพื่อจะดูว่ามีความเสี่ยงอาการบาดเจ็บจากการวิ่งหรือเปล่า แบ่งย่อยได้อีกเป็น\nอาการเท้าล้ม (Over Pronation)\nในเคสนี้ผมรอดไปครับ หมอบอกว่าลงน้ำหนักได้ดีทั้งสองข้างแบบ Neutral ไม่บิดเข้าบิดออกเลย\nความสมดุลของกล้ามเนื้อทั้งสองข้าง\nเคสนี้หมอจะดูจากอาการขาไขว้ (Cross Running) ครับ ซึ่งผมมีปัญหา ขาขวามีอาการไขว้เป็นพักๆ ซึ่งมีมัดกล้ามเนื้อที่มีปัญหาคือ Gluteus Medius, Gluteus Maximus ที่ทำให้เกิดอาการ Hip Drop วิ่งแล้วสะโพกตก\nในส่วนของการนี้คุณหมอแนะนำว่าให้ไป Weight Training เลย ซึ่งผมไม่ได้เล่น Weight มาหลายปีมากตั้งแต่เปลี่ยน Trainer หลายปีที่แล้ว ซึ่งหมอก็ให้โปรแกรมมาแก้เรื่องนี้คือ\nSquats เพื่อแก้ Gluteus Maximus หมอย้ำมากว่าต้องลงลึกๆ ตั้งฉาก 90 องศาเลย Abduction เพื่อแก้ Gluteus Medius แต่ต้องเล่นน้ำหนักเบามากๆ หรือจะใช้ยางยืดเปิดสะโพกแทนเอาก็ได้ และอย่างที่หมอแนะนำคือ ยังไงก็ต้องกลับมาพัฒนา Core body จะ Isometric Plank หรืออะไรก็ได้\nฟอร์มการวิ่งด้านข้าง\nจุดนี้เหมือนคุณหมอจะโฟกัสการลงน้ำหนักกับการยกเข่า แล้วหมอชมว่า ถือว่าเป็นคนน้ำหนักเยอะ แต่วิ่งดีนะ ท่าวิ่งนี้สวยเลย มีการเทน้ำหนักไปข้างหน้า วงสวย ดีดส้นดี ไม่ Overstride แทงเข่าได้ไกลใช้ Hip Flexor เป็น ถ้าเทียบน้ำหนักตอนนี้วิ่งได้ขนาดนี้ ถ้าตัวลีนแล้วจะวิ่งได้เร็วและแรงมาก… หมอชมมาขนาดนี้ ผมก็ลอยสิครับ 555\nในส่วนของการลงน้ำหนัก ยังลงที่ส้นอยู่ แต่ไล่เท้าได้เร็วมากจนเกือบๆ จะเป็น Mid Foot Strike แล้ว ซึ่งก็ไม่น่าต้องปรับอะไรแล้วเพราะไม่มีความเสี่ยงในการบาดเจ็บจากการลงน้ำหนักเลย\nตัว Core body อาจจะต้องดูว่าถ้าวิ่งนานๆ จะมีโยกหรือเปล่า ส่วนการแกว่งแขนนี่ใช้ได้แล้ว เป็นการแกว่งจาก Shoulder Joint แค่ระวังอย่าให้ Cross mid-line ก็พอ\nHealth Analysis ช่วงนี้คือ เหมือนถูกคุณหมอสัมภาษณ์เรื่องการกิน แล้วการที่คุณ กต เข้าไปนั่งฟังด้วยเลยเหมือนช่วยกันตอบเยอะมากๆ แต่คิดถูกมากๆ ที่เอาคุณ กต มานั่งฟังด้วย อันนี้รายละเอียดเยอะมาก แต่สรุปได้คร่าวๆ คือ ถ้าจะออกกำลังกายได้ Effective มากขึ้นยังไงก็ต้องลดน้ำหนักอยู่ดี\nLife Plan Summary ถึงจุดนี้เหมือน คุณหมอวางแผนชีวิตให้เลย ซึ่งคุณหมอก็วางให้สัมพันธ์กับ Goal ที่บอกไปก่อนหน้านี้แบ่งเป็น 3 แกนหลักๆ\nออกกำลังกาย\nไม่ต้องโฟกัสมากว่าต้อง Zone 2 แต่คือซ้อมไปปกติ ตามที่วางแผนมาให้เลย แต่ถ้ารู้สึกว่าที่เทสมาวันนี้มันเบาไปก็เอาตามความรู้สึกเลยก็ได้ แล้วเสริมด้วย Strength training ด้วย\nอีกส่วนที่เป็น Optional คือ NEAT (non-exercise activity thermogenesis) พูดให้เข้าใจง่ายๆ คือการขยับตัวระหว่างวัน เพราะบอกหมอไปว่าผมเป็นโปรแกรมเมอร์ครับ ถ้าใช้โต๊ะยืนได้จะดีมาก แต่ถ้าไม่ได้จริงๆ ก็ตั้งเวลาไว้แล้วออกไปขยับร่างกายบ่อยๆ\nการกิน\nส่วนนี้หมอแนะนำให้ไปเรียนรู้การแยกความรู้สึกของความหิว ความอิ่มดีๆ แล้วพยายามกินอยู่ที่ 80% ของความอิ่ม ถ้าจะ cut ให้เริ่มที่ Carb แต่ห้ามลดโปรตีนเด็ดขาด\nการนอน\nอันนี้ไม่ต้องทำอะไร เพราะนอนได้ดีอยู่แล้ว\nก็ประมาณนี้ครับสำหรับการไปทดสอบ VO2 max เอาจริงๆ คือประทับใจมากๆ เพราะได้คำตอบทุก Aspect ที่ตั้งใจจะไปถามเลย และรู้สึกว่าคุณหมอกับคุณนักวิทย์ก็ใส่ใจมากๆ เพราะถามเยอะมากกับช่วยคิดเยอะมาก ตอนนี้เลยได้การบ้านไปทำต่อกับไฟในการวิ่งลุกโชนขึ้นไปอีก\n","permalink":"https://yothinix-com.pages.dev/vo2max-test/","summary":"\u003ch2 id=\"ขอยอนความกอน-ถาใครสนใจแคเรองการตรวจ-vo2-max-จะขามสวนนไปเลยกไดครบ\"\u003eขอย้อนความก่อน ถ้าใครสนใจแค่เรื่องการตรวจ VO2 Max จะข้ามส่วนนี้ไปเลยก็ได้ครับ\u003c/h2\u003e\n\u003cp\u003eต้องย้อนไปว่าปีนี้ผมกลับมาวิ่งแล้วครับ หลังจากหยุดวิ่งจริงจังไปหลายปีมากๆ แล้วผมจะมีความคาใจอยู่นานตั้งแต่สมัยวิ่งไปถึง Half Marathon แล้วว่าผมไม่สามารถวิ่งยาวๆ จนจบได้เลย แต่เป็นวิ่งสลับเดินมาตลอด ถึงแม้จะพยายามเก็บระยะ จะพยายามซ้อมตามตารางแล้วก็เถอะ\u003c/p\u003e\n\u003cp\u003eจนกลับมาวิ่งรอบนี้ผมตั้งเป้าหมายง่ายมาก (น่าจะง่ายแหละ) คือขอแค่วิ่งยาวๆ จบ ไม่ต้องหยุดเดินตามระยะที่ต้องการได้ก็พอ ทีนี้พอเข้าโปรแกรมซ้อมกับนาฬิกา สิ่งที่ค้นพบหลังจากผ่านไปไม่กี่สัปดาห์คือ ผมกลับมา Loop เดิมคือยังวิ่งตามโปรแกรมซ้อมจนจบไม่ได้ Pace ลั่น จนหมดแรงแล้วก็เดินอีกแล้ว จนเริ่มเรียนรู้ที่จะคุม Pace ให้เป็นซึ่งเป็นจุดเปลี่ยนมาก เพราะผมเริ่มวิ่งได้ไกล ได้นานขึ้นเรื่อยๆ แล้วพัฒนาการมันเพิ่มขึ้นแบบรู้สึกได้\u003c/p\u003e\n\u003cp\u003eแต่พอผ่านไปได้ประมาณ 3/4 ของโปรแกรมมันก็ถึงจุดที่ผมกลับมาคาใจอีก ผมเริ่มที่จะรู้สึกว่า Hit-the-wall เหมือนมีกำแพงที่ข้ามไปไม่ได้คือไป Pace ที่ต้องการไม่ได้ซักที อีกจุดที่คาใจคือ เริ่มรู้สึกว่านาฬิกามันโชว์ Heart Rate Zone แปลกๆ เวลาวิ่งคือไป Zone 3-4 ทั้งๆ ที่ผมรู้สึกว่าเอะ มันก็ยังไม่เหนื่อยนี่หว่า แต่บางวัน Zone 4 ก็เหนื่อยมากๆ เลยรู้สึกว่ามันมีอะไรผิดปกติละ\u003c/p\u003e\n\u003cp\u003eจังหวะนั้นคือเริ่มมองหาตัวช่วยละ เลยไปเจอใน \u003ca href=\"https://www.youtube.com/watch?v=u-5UOPwCWHk\"\u003eThe Running Channel\u003c/a\u003e ว่ามันมีตรวจอะไรแบบนี้ด้วย หลังจากนั้นก็เริ่มหาข้อมูลเลยมาเจอของไทยมีหลายที่เลย แต่ผมเจอของ \u003ca href=\"https://www.facebook.com/HPTThailand\"\u003eHealth Performance Team\u003c/a\u003e กับ\u003ca href=\"https://www.facebook.com/akanismd\"\u003eคุณหมอแอร์\u003c/a\u003eที่เป็นนักกีฬาด้วย เลยตัดสินใจนัดเลย\u003c/p\u003e","title":"ผมไปตรวจ VO2 Max มาครับ แล้วมันดีมากๆ"},{"content":"ผมมีรถของตัวเองได้ตอนนี้ก็เกือบๆ จะครบหนึ่งปีละครับ สิ่งหนึ่งที่ขาดไม่ได้เลยนอกจากขับมันคือการดูแลรักษามันครับ แล้วไม่รู้ว่าผมโชคดีหรือโชคร้ายที่โตมาจนอายุ 30 กว่าเนี่ย ไม่เคยต้องช่วยพ่อแม่ล้างรถที่บ้านเลย เลยกลายเป็นว่าผมไม่รู้ว่าวิธีล้างรถที่ถูกต้องมันคือยังไง\nแต่แรกสุดเลยเนี่ยผมก็ไม่ได้ตั้งใจจะล้างเองหรอกครับ ผมก็เหมือนกับทุกๆ คนคือ คิดไว้ว่าจะเข้าร้าน Car care ใช้เงินแก้ปัญหาให้คนจัดการให้ สิ่งที่ผมทำก็คือ ผมทักไปหาเพื่อนรักผมคนนึงว่า\nผมจำได้แม่นเลยว่า ผมเกือบละ เกือบจะเข้าวงจรร้านล้างรถอัตโนมัติละ ที่เราแค่ขับเข้าไปในสายพาน แล้วปล่อยให้มันฉีดน้ำกับปั่นๆ ให้จนเสร็จ ผมจำได้ว่าจอดต่อคิวอยู่หน้าร้านแถวบ้านอยู่ประมาณ 5 นาที แล้วผมก็ทำการตัดสินใจที่ดีที่สุดครั้งนึงในชีวิตคือ ผมเลือกที่จะไม่รอแล้วขับกลับบ้านไปเลย\nที่ผมบอกว่าเป็นการตัดสินใจที่ดีที่สุดในชีวิตเพราะหลังจากนั้นผมเลยได้รู้จักคำว่า รอยขนแมว หรือ Scratch \u0026amp; Swirl ครับมันคือ รอยข่วนเล็กๆ ในชั้นแลกเกอร์ซึ่งมองผ่านๆ อาจจะไม่รู้สึกอะไร แต่ถ้ามันสะสมนานๆ เข้าตัวนี้แหละครับที่จะไปหักเหแสงที่ตกกระทบผิวสีรถ แล้วทำให้รถไม่เงา ซึ่งการล้างรถโดยการพารถไหลผ่านเครื่องให้มันปั่นอัตโนมัติให้เนี่ย ตัวสร้างรอยขนแมวชั้นดีเลย\nผมเป็นชาว Chemical Guys หลังจากนั้นก็เป็นช่วงเวลาที่ผมเริ่มศึกษาครับ ซึ่งผมเคยเล่าไปแล้วบางส่วนในบล็อก มือสมัครเล่นเมธอด ถ้าใครยังไม่ได้อ่านก็ลองไปดูได้ ในช่วงแรกๆ ผมมีเพื่อนอยู่ 2 คนครับที่ทำให้ผมรู้จักวิธีการล้างรถที่ถูกต้องสองคนนั้นชื่อว่า Joey กับ Henry จากช่อง Chemical Guys ครับ\nเพื่อนโจอี้ เพื่อนเฮนรี่\nด้วยความที่รถผมเป็นรถ Crossover เอาจริงๆ ทรงมันก็คล้ายๆ SUV เลยพยายามหาอะไรที่มันคล้ายๆ กัน คลิปแรกๆ ที่ผมดูในช่องนี้ผมจำได้แม่นเลยคือคลิปข้างล่างนี้ครับ ตัวผมน่าจะดูคลิปนี้เกินสิบรอบทั้งก่อนล้างหลังล้างรอบแรกๆ เพราะมันสอนอะไรผมเยอะมากและเพราะคลิปนี้เลยเป็นการเซต Stage ให้ผมเข้าสู่วงการนี้\nผมยึดวิธีการล้างตามคลิปนี้เป็นพื้นฐานมาจนถึงทุกวันนี้ครับ ไม่ว่าจะเป็น Wheel first, 2 Buckets Method, Pre-rinse, Top to Bottom ฯลฯ สิ่งที่ผมเห็นในคลิปนี้ไม่ใช่แค่ Process ครับแต่มันเป็น Practices ซึ่งตอนนี้พอมามองย้อนจริงๆ มันเหมือนการเขียนโปรแกรมที่เรามักจะมีคำพูดว่า “เขียนโปรแกรมได้ กับเขียนโปรแกรมเป็น”\nขยายความอีกนิดที่ผมบอกว่ามันเหมือนกับการเขียนโปรแกรมคือ ตอนเราเขียนโปรแกรมเนี่ย ถ้าเรามีปัญหา A→B ถ้าคิดแบบง่ายที่สุดคือเราต้อง do whatever it take ที่จะแก้ปัญหาเพื่อให้โปรแกรมได้ผลลัพธ์จาก input ไปเป็น output แบบที่เราต้องการใช่มั้ยครับ แต่ถ้าเรามีประสบการณ์มากขึ้นใช่ครับ มันไม่ใช่แค่จาก A→B สิ่งที่เวลาเราเขียนโปรแกรมมอง เราต้องมองว่า Code มัน Maintain ได้มั้ย, Design Principle ได้มั้ย, Performance ได้มั้ย, Testable มั้ย ซึ่งถ้าเราไม่ระวังเนี่ย Side effect ที่จะเกิดขึ้นก็คือ Technical dept ครับและยิ่งทำให้การเขียนโปรแกรมครั้งต่อๆ ไปที่ต้องยุ่งกับจุดนี้ยากขึ้นเรื่อยๆ\nกลับมาที่การล้างรถ ไอการล้างรถเนี่ยถ้าเปื้อนดินมา แค่เอาน้ำฉีดมันก็ (ดู) สะอาดครับ มัน (ดู) สะอาดตอนฉีดน้ำเสร็จนั่นแหละ แต่พอเราปล่อยทิ้งไว้ คราบน้ำก็จะมาละ แล้วพอเรามองดูดีๆ คราบหลายอย่างมันก็ยังอยู่ครับ เราก็เลยต้องมี Practices หลายๆ อย่างเกิดขึ้นมาเพื่อที่จะให้เราได้ผลลัพธ์ที่ดีที่สุดและเกิด Side effect น้อยที่สุดครับ ยกตัวอย่างเช่น ทำไมถึงต้องล้างจากบนลงล่าง เพราะว่าน้ำมันไหลจากบนลงล่างนั่นก็เหตุผลหนึ่ง แต่ที่สำคัญคือ ส่วนบนของรถจะสกปรกน้อยกว่าด้านล่างครับ และสิ่งสุดท้ายที่เราต้องการให้เกิดคือการ cross contaminate คราบดินโคลนหรือผงเบรคจากข้างล่าง ขึ้นไปข้างบน หรืออีกตัวอย่างนึง ทำไมถึงต้อง 2 buckets method เพราะเราหลีกเลี่ยง Side effect ที่เราไม่ต้องการที่สุดคือ Scratch \u0026amp; Swirl หรือรอยขนแมวให้ได้มากที่สุดครับโดยการหมั่นล้าง Wash mitt เราบ่อยๆ ระหว่าง Contact Wash ซึ่งถ้าเราไม่ป้องกันไว้แต่เนิ่นๆ รอยขนแมวพวกนี้ก็จะสมเป็น Technical debt ต่อไปให้รถเราไม่เงา หรือแม้กระทั่งตัวอย่างสุดท้ายว่า ทำไมล้างเสร็จเราต้องลง Wax/Sealant ด้วย ก็เพื่อที่จะปกป้องผิวรถให้คราบสกปรกมันติดยากขึ้น ทำให้การล้างครั้งต่อๆ ไปง่ายขึ้น เหมือนกับที่เราเพิ่ม Unit tests ไว้เพื่อให้โค้ดมัน maintain ง่ายขึ้นกับการต่อเติมในอนาคตครับ\nจากตัวอย่างจะเห็นว่านี่แหละครับ มันไม่ใช่แค่ Process A→B แต่ในนั้นถ้าเรามองดีๆ มันมี Practices หรือ Art หลายๆ อย่างที่ช่วยให้เราได้ผลลัพธ์ที่ดีขึ้นด้วยครับ\nโลกนี้ไม่ได้มีแค่ Chemical Guys พอผ่านช่วงสามเดือนแรก ก็เป็นช่วงที่เริ่มขยายจักรวาลไป Youtube channel อื่นๆ แล้วไม่ว่าจะเป็น Vermijl Car Detail, Pan the organizer, The Rag Company, Proper Care หรือจะเป็น Channel คนไทยอย่าง O2CARS แม้กระทั่งกลุ่ม Facebook: TWCC : Thai Washer Car Club ก็เป็นแหล่งความรู้ให้ผมเยอะมากครับ จนเริ่มบอกไม่ถูกว่า รู้อะไรมาจากที่ไหน แต่สิ่งสำคัญที่ได้มายิ่งกว่าความรู้คือการโดนป้ายยาครับ ซึ่งพอเรา Expose ตัวเองมาเกินกว่า 1 Brand ก็จะเริ่มมีความอยากลองนั่น ลองนี่เต็มไปหมด เห็นคนอื่นเค้ามี Water Beading ก็อยากลอง Wax ตัวนั้นบ้าง Sealant ตัวนี้ก็ดี\nเอาจริงๆ ต้องขอบคุณคุณแฟนอย่าง กต มากๆ ที่ห้ามไว้ว่าให้ใช้ของที่มีให้หมดก่อน โดยเฉพาะ Wax/Sealant อย่าง Butter Wet Wax หรือ JetSeal ถึงแม้จะเติมใส่รถเรื่อยๆ ในช่วงแรกๆ พยายามใช้หนักมาก แต่นี่ยังเหลืออีกเกินครึ่งขวด จนกระทั่งเข้าหน้าฝนแบบจริงจัง ตกวันเว้นวันนี่แหละถึงเริ่มเปิดจักรวาลมากขึ้น\nWater Beading ที่เราตามหา\nอย่างแรกที่เริ่มเปิดหลังจากออกมาจากโลกของ Chemical Guys คือ P\u0026amp;S Bead Maker ครับ อยากสัมผัสคำว่า Water Beading ที่ราคาถูกที่สุด แต่ยังคงมาตรฐานสากลอยู่ แล้วก็ไม่ผิดหวังเลย เพราะลุยฝนในช่วงนั้นนี่น้ำเป็นหยดกลมสวยงามมาก ผิดกับ JetSeal ที่เป็น Sheeting มาตลอด\nอย่างที่สองคือน้ำยาเคลือบกระจกครับ จริงๆ ดูไว้หลายเจ้ามากทั้ง RainX, CarPro FlybyForte หรือแม้กระทั่ง Chemical guys HydroView แต่สุดท้ายก็มาจบที่ Glaco ทั้งระบบตั้งแต่เตรียมผิวกระจก Compound, เคลือบด้วย Ultra Glaco, Maintain ด้วย Glaco De Cleaner ซึ่งทำให้ผมได้สัมผัสกับหยดน้ำไหลผ่านกระจกไปแบบน่ารักมาก แล้วไม่เคยเห็นน้ำเป็นแผ่นในกระจกอีกเลย\nที่มาที่สุดท้ายเลือก Glaco มาจากคลิปนี้ครับ\nแต่สิ่งที่มันคาใจอยู่นานมาก ช่วง 6 เดือนนั้นคือ ถึงแม้เราจะมีกระบอกฉีดโฟมที่ดีที่สุดในโลกอย่าง MJJC Foam Canon Pro แต่ก็ไม่สามารถสร้าง Foam หนาๆ ได้แบบที่ตั้งใจ จนสุดท้ายต้องอัพเกรดเครื่องฉีดน้ำไปใช้ตัวแรงอย่าง Flow Energy M9 130 bar จากตัวเก่า Bosch Aquatek 100 bar ซึ่งเป็นการอัพเกรดที่คุ้มค่ามาก นอกจากจะได้โฟมหนาแบบที่ต้องการแล้ว ยังเสียงเบาลงนิดนึงด้วยถ้าเทียบกับตัวเดิมๆ\nช่วงนี้ถ้ามามองย้อนดูเป็นช่วงที่ Satisfy need ตัวเองสูงมาก เพราะตอนเราเริ่มต้นใหม่ๆ เราจะใช้อุปกรณ์ที่ราคาไม่แพงมากเพราะไม่รู้ว่าเราจะจริงจังรึเปล่า เวลาถอยจะได้ไม่เจ็บตัวมาก แต่พอปลดล็อกแบรนด์หรือรู้แล้วว่าของที่ดีที่สุดในหมวดนั้นๆ คืออะไร แล้วหามา Satisfy ตัวเองได้ ผลลัพธ์ที่ได้มันโคตรน่าพอใจเลยครับ แต่ข้อเสียคือ มันเริ่มเป็นจุดแรกที่ผมรู้สึกอิ่มตัวละ เพราะเราได้ทุกอย่างที่เราต้องการแล้ว\nเข้าสู่โลกของ Rinseless ถึงจุดนี้น่าจะเริ่มเห็นแล้วใช่มั้ยครับว่า มันไม่ใช่แค่ Practice ละ มันเป็นอุปกรณ์เต็มบ้านละที่ทำให้งานมีประสิทธิภาพซึ่งถามว่ามันดีมั้ย มันก็ดีแหละ แต่ก็เป็นช่วงเดียวกันที่ผมเริ่มจะ Realize ว่ากว่าจะล้างได้แต่ละทีนี่ เสีย Overhead เตรียมของเกือบชั่วโมง ล้างอีก 2 ชั่วโมง ซึ่งมันใช้เวลานานมากๆ แล้วคือ ล้างเสร็จผลลัพธ์ถึงจะพอใจมา แต่ก็หมดแรงมากๆ เช่นกัน นี่ยังไม่พูดถึงตอนเก็บของที่ล้างมาเหนื่อยๆ ต้องเก็บอุปกรณ์ทั้งหมดอีก ช่วงนี้แหละครับที่ทำให้ผมค้นพบอาจารย์คนใหม่ผม คนนั้นมีชื่อว่า Yvan Lacroix ครับ\nอาจารย์ไอแวน\nจริงๆ ต้องย้อนไปช่วงหน้าฝนหนักๆ เนี่ย ผมเริ่มมองหาวิธีที่จะล้างรถได้เร็วๆ เพราะแปปๆ ฝนก็ตก แต่เราอยากให้รถสะอาดตลอด ช่วงแรกๆ คือไปทาง Quick Detailer แต่ตัว Quick detailer เองก็ไม่สามารถจะ Lift คราบไคลที่เกิดจากน้ำผสมฝุ่นแห้งติดรถได้มากครับ ผมเลยมองไปที่ตัวเลือกที่สองคือ Waterless ที่เป็นอารมณ์ประมาณ Spray ฉีดแล้วเช็ดที่ Emulsify คราบขึ้นมาได้ดีกว่า แต่ส่วนตัวผมก็ยังไม่ชอบ Waterless มากเพราะรู้สึกว่ามันทิ้งคราบน้ำยาไว้หลังจากเช็ดระดับนึงอยู่ ถึงจะพยายาม Buff ออกแล้ว แล้วก็เปลืองด้วยครับ ล้างรอบคันด้วย Waterless เนี่ยแทบจะหมดไป 1/5 ของขวด 16oz ละ นั่นเป็นจุดที่ทำให้ผมมาเจอสิ่งที่เรียกว่า Rinseless Wash ครับ\nต้องบอกว่าตอนแรกๆ ที่ผมลอง Rinseless Wash กับ ONR เนี่ย ผมไม่ประทับใจเลยครับ เอาตั้งแต่การ Mix น้ำยาตอนแรกที่อัตรส่วน 1:256 ซึ่งมันไม่ใช่อะไรที่จำได้ง่ายๆ ในตอนแรก ทำให้เราก็ไม่มั่นใจว่าน้ำยาได้อัตราส่วนที่ต้องการรึเปล่า เพราะผสมเสร็จมันไม่ได้ลื่นๆ เหมือนสบู่เลยครับ รู้สึกแทบไม่ต่างจากน้ำเปล่าเลยไม่รู้ว่ามันจะลื่นพอที่จะทำ Contact wash โดยไม่เกิด Scratch ได้มั้ย และถึงแม้จะผลัดๆ ใช้ผ้าหลายๆ ผืนแล้ว แต่รู้สึกว่าคราบไคล มันไม่ค่อยออกเท่าไร สุดท้ายก็มาล้างใหญ่จัดเต็มระบบ Foam Canon อยู่ดีถึงรู้สึกว่าสะอาดกว่าแล้วผมก็ลืม Rinseless ไปเลย\nRinseless ครั้งแรกสุด\nผ่านมาหลายเดือนจนผมกลับมาอีกครั้ง แล้วมารีวิวว่าตัวเองพลาดอะไรไป (วิธีเดิมครับ ผมดูทุกคลิปใน Youtube ที่เจอจากการ Search ว่า Rinseless Wash) ทำให้ผมเจอว่าสิ่งที่ผมพลาดไปมากๆ ในครั้งที่ผมไม่ประทับใจคือ ผมไปใช้ Foam Sprayer ทำ Pre-rinse ครับ เลยทำให้ตัวน้ำยามันไม่ได้กระจายตัวไป Emulsify คราบเท่าที่ควร พอรอบนี้กลับมาใช้หัว Spray ธรรมดาๆ นี่แหละ กลายเป็นการ Emulsify คราบทำได้ดีกว่ามากๆ อีกอย่างที่ผมพลาดไปคือผ้ายังไม่หมาดพอครับ ทำให้พอมันชุ่มๆ เนี่ยมันดึงคราบติดออกมาได้น้อยกว่าตอนผ้าหมาดมากๆ (Yvain จะใช้คำว่า On the verge of dripping) เลยทำให้รู้สึกว่าล้างไม่สะอาดเลยในตอนก่อนหน้านี้\nพอรู้จุดที่พลาดก็ลอง Practice ครับ ซึ่งผลลัพธ์มันก็ดีขึ้นมากครับเพราะพอปล่อยให้ Pre-rinse มันอยู่กับผิวนานขึ้น มันยิ่ง Emulsify คราบขึ้นมากับน้ำยา พอเช็ดแล้วเห็นน้ำเป็นสีขุ่นๆ นี่คือรู้เลยว่าเวิร์คละ ยิ่งพอเริ่ม Standardize practice ใช้ถ้วยตวงกับขวดน้ำลิตรช่วยเป็น 1 ฝาตวงน้ำยาต่อน้ำเปล่า 4 ขวดลิตรการเตรียมก็ยุ่งยากน้อยลงไปอีก กลายเป็นนี่เป็นวิธีหลักที่ผมใช้ล้างรถตอนนี้เลยครับ สามารถจบงานได้ในเวลาไม่ถึงชั่วโมงนับตั้งแต่ เตรียมน้ำยาไปจนถึงเช็ดแห้ง ข้อเสียเดียวที่คิดออกตอนนี้คือพอมาใช้ Spray ธรรมดานี่เมื่อยมือมากครับ ซึ่งมันก็มีวิธีแก้ (ด้วยเงิน) แหละ แต่ตอนนี้อยาก Keep It Simple Stupid ก่อนเพื่อที่จะได้ keep momentum ของการดูแลรถต่อไป ทุกที่ ทุกเวลา\nสภาพปัจจุบัน\nหลังจากเล่ามาทั้งหมด น่าจะเห็นแล้วใช่มั้ยครับว่าการล้างรถเนี่ย มันไม่ได้มีแค่ล้างรถ มันมี Practices ที่พัฒนาขึ้นทุกยุค มันมี Process ที่เราสามารถพัฒนาให้มีประสิทธิภาพได้ มันมี Reward ที่ให้เราได้มองดูรถเราที่มันสะอาดในทุกๆ วันและที่สำคัญที่สุด มันมีอะไรให้ผมเรียนรู้ได้เรื่อยๆ ไม่หยุดเลยครับตลอดหลายเดือนที่ผ่านมา\nและสำหรับใครที่อ่านมาจนถึงจุดนี้แล้วรู้สึกว่า ผมพูดอะไรฟะ มีแต่ศัพท์เฉพาะก็ไม่ต้องตกใจไปครับ เพราะมีเรื่องระหว่างทางที่ผมไม่ได้อธิบายหลายอย่างมากทั้ง Practice ระหว่างล้าง Technology ที่พัฒนาขึ้นมาตลอดหลายปี ฯลฯ ซึ่งบล็อกเกี่ยวกับการล้างรถแบบ Detailing ผมไม่ได้จบแค่นี้แน่นอนครับ บอกไว้ล่วงหน้าเลยว่าจะมีอีก 3 บล็อกตามมาหลังจากนี้คือ\nFull scale wash, clay and seal — จะลงรายละเอียดเครื่องมือ, สารเคมี, Practices และ Process ในการล้างแบบเต็มระบบครับ Interior detailing — จะเห็นว่าผมไม่ได้เล่าเรื่องการทำความสะอาดภายในเลย เพราะว่าอันนี้เป็นอีกศาสตร์นึงเลย คิดว่าจะมาลงรายละเอียดในบล็อกนี้ Rinseless wash — จะเหมือนบล็อก Full scale เลยครบ แต่เป็นอีก Paradigm ที่ผมตกหลุมรักมันอยู่ตอนนี้ ซึ่งถ้าสนใจก็คอยติดตามต่อได้ในบล็อกนี้เลยครับ หรือถ้าใครมีคำถามหรืออยากได้คำแนะนำอะไรก็ทิ้งคอมเม้นทิ้งไว้ได้ครับผม\n","permalink":"https://yothinix-com.pages.dev/detailing-journey/","summary":"\u003cp\u003eผมมีรถของตัวเองได้ตอนนี้ก็เกือบๆ จะครบหนึ่งปีละครับ สิ่งหนึ่งที่ขาดไม่ได้เลยนอกจากขับมันคือการดูแลรักษามันครับ แล้วไม่รู้ว่าผมโชคดีหรือโชคร้ายที่โตมาจนอายุ 30 กว่าเนี่ย ไม่เคยต้องช่วยพ่อแม่ล้างรถที่บ้านเลย เลยกลายเป็นว่าผมไม่รู้ว่าวิธีล้างรถที่ถูกต้องมันคือยังไง\u003c/p\u003e\n\u003cp\u003eแต่แรกสุดเลยเนี่ยผมก็ไม่ได้ตั้งใจจะล้างเองหรอกครับ ผมก็เหมือนกับทุกๆ คนคือ คิดไว้ว่าจะเข้าร้าน Car care ใช้เงินแก้ปัญหาให้คนจัดการให้ สิ่งที่ผมทำก็คือ ผมทักไปหาเพื่อนรักผมคนนึงว่า\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/detailing-journey/Screenshot-2566-11-04-at-11.22.34_hu_42e5e151ad17f2f9.webp\"\n       srcset=\"/detailing-journey/Screenshot-2566-11-04-at-11.22.34_hu_42e5e151ad17f2f9.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"526\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eผมจำได้แม่นเลยว่า ผมเกือบละ เกือบจะเข้าวงจรร้านล้างรถอัตโนมัติละ ที่เราแค่ขับเข้าไปในสายพาน แล้วปล่อยให้มันฉีดน้ำกับปั่นๆ ให้จนเสร็จ ผมจำได้ว่าจอดต่อคิวอยู่หน้าร้านแถวบ้านอยู่ประมาณ 5 นาที แล้วผมก็ทำการตัดสินใจที่ดีที่สุดครั้งนึงในชีวิตคือ ผมเลือกที่จะไม่รอแล้วขับกลับบ้านไปเลย\u003c/p\u003e\n\u003cp\u003eที่ผมบอกว่าเป็นการตัดสินใจที่ดีที่สุดในชีวิตเพราะหลังจากนั้นผมเลยได้รู้จักคำว่า รอยขนแมว หรือ Scratch \u0026amp; Swirl ครับมันคือ รอยข่วนเล็กๆ ในชั้นแลกเกอร์ซึ่งมองผ่านๆ อาจจะไม่รู้สึกอะไร แต่ถ้ามันสะสมนานๆ เข้าตัวนี้แหละครับที่จะไปหักเหแสงที่ตกกระทบผิวสีรถ แล้วทำให้รถไม่เงา ซึ่งการล้างรถโดยการพารถไหลผ่านเครื่องให้มันปั่นอัตโนมัติให้เนี่ย ตัวสร้างรอยขนแมวชั้นดีเลย\u003c/p\u003e\n\u003ch1 id=\"ผมเปนชาว-chemical-guys\"\u003eผมเป็นชาว Chemical Guys\u003c/h1\u003e\n\u003cp\u003eหลังจากนั้นก็เป็นช่วงเวลาที่ผมเริ่มศึกษาครับ ซึ่งผมเคยเล่าไปแล้วบางส่วนในบล็อก \u003cstrong\u003e\u003ca href=\"/amateur-method/\"\u003eมือสมัครเล่นเมธอด\u003c/a\u003e\u003c/strong\u003e ถ้าใครยังไม่ได้อ่านก็ลองไปดูได้ ในช่วงแรกๆ ผมมีเพื่อนอยู่ 2 คนครับที่ทำให้ผมรู้จักวิธีการล้างรถที่ถูกต้องสองคนนั้นชื่อว่า Joey กับ Henry จากช่อง \u003ca href=\"https://www.youtube.com/@ChemicalGuys\"\u003eChemical Guys\u003c/a\u003e ครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/detailing-journey/Screenshot-2566-11-04-at-11.33.54_hu_a3e69c7028075917.webp\"\n       srcset=\"/detailing-journey/Screenshot-2566-11-04-at-11.33.54_hu_fe6c4d924fe0cf28.webp 480w, /detailing-journey/Screenshot-2566-11-04-at-11.33.54_hu_84aa4d648466dd85.webp 960w, /detailing-journey/Screenshot-2566-11-04-at-11.33.54_hu_a3e69c7028075917.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"744\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eเพื่อนโจอี้ เพื่อนเฮนรี่\u003c/em\u003e\u003c/p\u003e","title":"แชร์ประสบการณ์การเดินทางสู่ DIY Car Detailer ตลอด 1 ปีที่ผ่านมา"},{"content":" 💡 TL;DR How I utilize Notion for everyday work\nจะนับว่าบล็อกนี้เป็นภาคต่อ ของต่อของต่อของซีรีย์บล็อกที่ผมเล่าว่าใช้ Bullet Journaling ยังไงมาตลอดหลายปีก็ได้ แล้วผมใช้ System นี้มาตั้งแต่ประมาณช่วงปลายปี 2021 จนถึงปัจจุบัน ถึงแม้มันจะมีการปรับเปลี่ยนรูปมาเรื่อยๆ แต่มันก็ได้พิสูจน์แล้วว่า มันช่วยผมจำและทำงานได้ดีมาตลอดหลายปีที่ผ่านมา และแม้กระทั่งบล็อกนี้เองก็เขียนอยู่บน Notion เป็น First draft เช่นกัน\nFirst Version ต้องบอกก่อนว่าก่อนหน้าจะมาอยู่บนนี้เป็นยุคที่ผม Hybrid อยู่บน Notion + Physical Notebook มาก่อน แต่ปัญหาหลักที่เจอคือ พอมันต้องแยกสองโลก ชีวิตจะเริ่มหาของยากขึ้นเรื่อยๆ ถึงแม้ผมจะเคยเชื่อว่าเราควรจะอยู่ในโลก Physical แต่ด้วยธรรมชาติของงาน Software ต้องอยู่บนคอมพิวเตอร์เกือบตลอด ต้องเก็บลิ้งค์หรือ Code snippet มันเลยทำให้ไม่สามารถไปใช้สมุดได้เต็มตัว จนถึงจุดนึงผมยอมแพ้แล้วย้ายกระบวนการในสมุดมาอยู่ใน Notion ทั้งหมด\nด้วยความที่ทีมที่ผมทำงานด้วยยังอยู่บนรอบ Sprint เพราะฉะนั้นการแบ่ง Section หลักๆ จะยังเป็น Sprint based อยู่ แต่จะมี Highlight ว่าวันไหนเป็นวันหยุดด้วยการเปลี่ยนวันเป็นสีแดงไว้ด้วย แต่ก็จะมีความใช้ practices ของ Bullet Journaling อยู่คือเขียนวันของทั้งเดือนลงมาเลยทั้งหมดในหน้าเดียว วิธีนี้ช่วยให้เห็นภาพรวมของทั้งเดือนว่ามันมี Event อะไรบ้าง แล้วสิ่งที่ Notion มาช่วยเติมเต็มการทำ bullet journaling คือการที่เราสามารถ Merge ตัว Monthly Log กับ Daily Log เข้าด้วยกันได้แบบแนบเนียนมาก โดยการใช้ Toggle List ครับ\nความดีงามของ Toggle List คือการที่มัน Encapsulate ข้อมูลที่เกี่ยวกับวันนั้นไว้ในตัวเองซ้อนเป็น Level ได้เลยทำให้จากแต่ก่อนต้องมีหนึ่งหน้าในสมุด dedicate ให้กับ Monthly log แล้วตัว Daily Log ก็ขยายไปเรื่อยๆ สองอย่างนี้ก็มารวมกันได้\nอีกหนึ่งฟีเจอร์ที่ดีงามมากของ Notion คือ To-do list เลยครับเป็นอีกฟีเจอร์นึงที่แมพลงกับ Tasks ใน Bullet Journal พอดิบพอดี และความดีงามคือนอกจากจะมี checkbox ให้กดข้างหน้าแล้ว พอกดแล้วยัง fade ตัวหนังสือของ task นั้นให้เป็นสีเทาด้วย เรียกได้ว่าให้เราโฟกัสเฉพาะงานที่ยังไม่เสร็จ ตัวที่เสร็จแล้วก็ลืมมันไปได้เลย\nSecond Version หลังจากใช้งานเวอร์ชั่นแรกมาซักพัก ผมเริ่มจะรู้ตัวว่ามันมี Monthly Log อีกแบบด้วยจริงๆ ต้องบอกว่าอารณ์มันจะกึ่งๆ Future Log คือ เรารู้ว่ามันเป็นสิ่งที่ต้องทำเดือนนั้นแหละ แต่ยังไม่รู้ว่าจะทำวันไหน แล้วการจะไปยัดวันใส่มันเลยใน Version แรกมันทำไม่ได้เลยเกิดการจัดระเบียบ Section ใหม่โดยแยกในเดือนเดียวแบ่งเป็น Monthly Log กับ Daily Log ไปเลย ซึ่ง Monthly Log นอกจากจะเป็นที่รวม Tasks ที่ต้องทำภายในเดือนนั้นแล้ว ยังมีอีกฟีเจอร์ที่เติบโตขึ้นมาตามการใช้งานซึ่งก็คือ Page ครับ\nตัว Page ที่ผมใช้ใน Monthly Log จะเป็นที่รวบรวมเรื่องที่เกี่ยวข้องกัน แล้วแทนที่จะเขียนมันกระจายไปในแต่ละวัน ซึ่งทำให้ชีวิตลำบากมากๆ กลายเป็นทุกอย่างจะถูกรวบรวมอยู่ในเพจๆ เดียวแทน ผมใช้เพจหลักๆ กับ Project, Research topic หรือเวลาไปเรียน Course อะไรก็จะรวบไว้ในนี้เลย พอรวบไว้ใน page เดียวแล้วแต่ละวันมันเลยกลายเป็นการ reference กลับไปหาเพจผ่านฟีเจอร์ Mention to a page แล้วเป็นการจดโน๊ตสั้นๆ แทนว่าวันนั้นทำอะไรเกี่ยวกับ page นี้\nอีกวิวัฒนาการที่เกิดขึ้นในช่วงเวอร์ชั่นที่สองคือ พอเราเริ่มใช้ Toggle list แทน Tasks ในแต่ละวันเพราะมันต้องการ detail มากกว่านั้นด้วย กลายเป็นว่าเราสูญเสียความสามารถในการติ๊ก To-do ไปแทน ซึ่งแรกๆ ผมก็แก้ text ของ Toggle list นั้นให้ขีดฆ่าแล้วเปลี่ยนเป็นสีเทาเอง แต่รู้สึกว่ามันใช้พลังงานเยอะเกินไป เลยกลายเป็นว่ามาจบที่การใช้ emoji prefix convention แทน 2 แบบคือ ✅ สำหรับ Task ที่เสร็จแล้วกับ 🚧 สำหรับ Task ที่ยังทำค้างอยู่ แล้วต้องทำต่อวันต่อไป\nThird Version เวอร์ชั่นถัดมาอาจจะเรียกว่า Minor change ก็ได้ เกิดจากตอนที่เปลี่ยนงาน แล้วมันมีของที่ต้องรู้ใหม่เยอะมากๆ เลยทำให้มีพวก Note ไว้คอยจดว่าเรียนรู้อะไรใหม่ปนกับ Tasks มากขึ้นเรื่อยๆ แล้วมันเละเทะมาก เลยเกิด Section ย่อยในแต่ละวันขึ้นมาเป็น #learntoday ซึ่งก็ใช้ Toggle List ทำการ encapsulate เหมือนเดิมมาช่วยให้แยกสิ่งที่ต้องโฟกัสแต่ละอย่างออกจากกัน\nอีกอย่างนึงที่เริ่มใช้เยอะในเวอร์ชั่นนี้คือ Horizontal Rules มาช่วยแบ่ง Section ในหนึ่งวัน เพราะเริ่มมี Context มากขึ้นแล้วการ Encapsulate ผ่าน Toggle List มันลึกไป แต่ Practice นี้ใช้ไม่ได้นานก็เลิกๆ ไป แล้วกลับไป Encapsulate เหมือนเดิม เพราะสุดท้ายแล้วเราไม่ได้อยากดูทุกอย่างตลอดหรอก แต่ถ้าอยากดูจริงๆ ก็กางเอาก็ได้\n4th Version ถ้านับเวลาจริงๆ ต้องบอกว่าหลังจากปรับเป็น Version 2,3 นี่ก็ไม่ได้ปรับรูปแบบอะไรในนี้เลยมาหลายเดือนมากๆ จนกระทั่งมามองย้อนกลับดูแล้วเจอปัญหานึงว่า หาที่โน๊ตที่ประชุมไว้ไม่เจอ ซึ่งก่อนหน้านี้เวลาจดโน๊ตประชุมจะมีอยู่ 2 แบบใช้ปนๆ กันไปคือ ถ้าไม่แยก Page ประชุมไปเลยก็เป็น Toggle List ซึ่งสุดท้ายหลายครั้งก็ Convert ไปเป็น Page ด้วย\nแต่พอมันเป็น Page ที่อยู่ในแต่ละวันแล้วการจะหามันเจอนี่ยากมาก ถ้า search ไม่เจอจริงๆ ก็ต้องมากดกางดูใน Page Hierachy ในเมนูทางซ้ายซึ่งเริ่มไม่สะดวกละ เลยทำให้สุดท้ายแยกออกมาเป็น Section: Meetings สำหรับเก็บโน๊ตประชุมไปเลย แล้วก็ใช้เป็น Toggle List ไปก็แก้ปัญหาที่หาโน๊ตประชุมไม่เจอใน Daily Log ไปได้ละ\nอีกสิ่งหนึ่งที่ Introduce มาในเวอร์ชั่นนี้คือตัว Story ครับ มันเกิดจากปัญหาว่าเวลาทำงานเรื่องๆ นึงมันไม่ได้จบในวันเดียว แล้ววันนึงก็ทำอะไรหลายอย่างมาก การจะ Keep track ว่าเราทำแล้ว Progress ถึงไหน เหลืออะไรบ้างนี่ ถ้าต้องดูจาก Daily Log ทุกวันมารวมกันก็ลำบากอยู่ เลยเกิดมาเป็น Section: Story สำหรับเก็บเรื่องที่ทำไปเลย\nวิธีนี้คือ Knowledge ที่เกี่ยวกับการทำเรื่องนั้นๆ จะถูกรวบมาไว้ที่เดียวเลย ทำให้เวลาดูภาพรวมมันง่ายขึ้น ส่วนในแต่ละวันก็จะเป็นโน๊ตสั้นๆ ว่าวันนี้ทำอะไรไปแทน ซึ่งจะมาอัพเดทตอนช่วง Wind down ในแต่ละวัน แล้วใช้งานเป็นหลักตอน Daily meeting ในวันถัดไป\nความดีงามอีกอย่างของการแยก Section: Story ออกมาคือ มันทำให้กลับมาย้อนดูได้ง่ายมากว่าเราทำอะไรไปตอนเดือนไหน ช่วยให้เขียน Performance Review ตัวเองง่ายขึ้น แล้วเสริมสร้าง self esteem นิดหน่อยว่าเรายังทำอะไรเป็นชิ้น เป็นอันบ้างนะ\nอย่างสุดท้ายที่ Introduce มาในเวอร์ชั่นที่ 4 คือการกลับมาทำ Future Logs ครับ มันเกิดจากปัญหาที่ว่าอยู่ดีๆ ปีนี้ก็ถูกเชิญไปงานแต่งงานเยอะมาก แล้วเริ่มรู้ตัวว่ามีเรื่องบางอย่างที่ต้องแพลนไปไกลกว่าเดือนนี้แล้วเลยต้องแยกออกมาเป็นเป็น Page ใหม่ที่มีศักดิ์พอๆ กับ Monthy Log ในแต่ละเดือนเลย\nConclusion ตอนนี้ผมอยู่ในเวอร์ชั่นที่ 4 ครับ ณ วันที่เขียนบล็อกนี้ ก่อนจบผมสรุปให้อีกทีว่ามาถึงเวอร์ชั่นปัจจุบันตอนนี้ Structure มันเป็นยังไงบ้าง\nเริ่มจากมี Root Page ชื่อ Journal แล้วข้างในแบ่ง sub-page เป็นรายเดือนเช่น January 2023, February 2023 แล้วก็มีอีกเพจชื่อ Future Logs อยู่บนสุด แล้วพอหมดปีก็สร้าง Page ใหม่รวบ Page รายเดือนเข้าด้วยกันตามปี\nFuture Logs เพจนี้มีไว้ในการเก็บเรื่องราวที่ไกลเกินกว่าเดือนปัจจุบัน ซึ่งส่วนใหญ่จะเป็นการนัด Event ต่างๆ แบ่ง Section ได้ตามใจชอบถ้ามันพอจะ Group ได้นะ\nMonthly Logs (\u0026lt;Month\u0026gt; \u0026lt;Year\u0026gt;) เพจนี้จะเก็บเรื่องราวในแต่ละเดือนจะสร้างใหม่ทุกๆ ต้นเดือน โดยแบ่ง Section ข้างในออกเป็น 4 Section\nIdeas \u0026amp; Tasks — ไว้เก็บอะไรที่นึกขึ้นได้ อะไรที่อยากทำในเดือนนั้นแต่ยังไม่รู้จะทำเมื่อไร หรือบางทีเกิน Scope ที่จะทำได้ในหนึ่งวันก็เอามาโยนไว้ที่นี่ ตรงนี้คือไม่มีกฏเลย อยากโยนอะไรก็โยนมาใส่จะทำ Bullet, Toggle List, Page, Callout แล้วแต่อารมณ์เลย\nStory — ไว้เก็บเรื่องที่เกี่ยวกับงานหลักที่ทำในเดือนนั้นๆ ที่เกิน Scope ของวันไปแล้ว จะทำเป็น Toggle List, Page ก็ได้แล้วแต่อารมณ์ ข้างในจะใส่ Note, รูปภาพ, Todo list ฯลฯ มี emoji convention 2 อย่างคือ ถ้ายังทำอยู่ใส่ 🚧 แต่ถ้าทำเสร็จแล้วให้ใส่ ✅\nMeetings — ไว้จดโน๊ตเกี่ยวกับที่ประชุมหรือคุยกับใครก็ตามที่มันออกแนว “ประชุม” ตัวนี้ส่วนใหญ่ใช้ Toggle List แล้ว Convention หลักๆ คือชื่อต้องเป็น 📅[\u0026lt;meeting-date\u0026gt;] \u0026lt;meeting name\u0026gt; ข้างในก็จดตามอัธยาศัยเลย\nDaily Logs\nตัวนี้แบ่งเป็น 2 ส่วนคือ Structure กับ detail แต่ละเพจ ในส่วนของ Structure จะเป็น List ของ Toggle List เรียงไปตั้งแต่วันที่ 1 จนถึงวันสุดท้ายของเดือน แล้วใส่วันกำกับไปด้วย ถ้าเป็นวันหยุด ตรงนี้จะใช้เป็นสีแดง\nในส่วนของ Structure ในแต่ละวันอันนี้ Free style เลยครับ ข้างบนเป็นแค่ตัวอย่างแบบนึง แต่ถึงเวลาจริง ผมก็ไม่ได้ทำแบบนี้ตลอด อยากจะทำ Todo list อยากจะใช้ Toggle list หรือจะแบ่ง Section ข้างในแต่ละวันอีก ไม่มีกฏตายตัวเลย สำคัญคือเอาที่มีประโยชน์กับเรา แล้วช่วย off-load สิ่งที่อยู่ในหัวเราออกไปได้ คำแนะนำกว้างๆ คือ ถ้าเป็นอะไรที่เราต้องกลับมาดูทีหลัง พยายามใส่ keyword เข้าไปให้ unique พอที่เราจะ search เจอทีหลังได้ด้วย\nประมาณนี้ครับ ผมเชื่อว่าแต่ละคนมีวิธีในการจดอะไรแบบนี้คล้ายๆ กันอยู่แล้ว แต่อาจจะมี Variant ต่างกันไปนิดๆ หน่อย แต่คิดว่าน่าจะพอได้อะไรกลับไปบ้างแหละ สิ่งสำคัญอีกอย่างที่ไม่ได้พูดข้างบนคือ ถ้าเราคิดว่า System เราเวิร์คอยู่แล้ว บางทีการหันกลับมามองมันอีกมุมบ้างเราอาจจะค้นพบวิธีที่มันดีกว่าก็เป็นได้ เหมือนกับคำกล่าวที่ว่า\n💡 The only thing to prevent better is good enough\n","permalink":"https://yothinix-com.pages.dev/working-how-to-work/","summary":"\u003cblockquote\u003e\n\u003cp\u003e💡 TL;DR How I utilize Notion for everyday work\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eจะนับว่าบล็อกนี้เป็นภาคต่อ ของต่อของต่อของซีรีย์บล็อกที่ผมเล่าว่าใช้ Bullet Journaling ยังไงมาตลอดหลายปีก็ได้ แล้วผมใช้ System นี้มาตั้งแต่ประมาณช่วงปลายปี 2021 จนถึงปัจจุบัน ถึงแม้มันจะมีการปรับเปลี่ยนรูปมาเรื่อยๆ แต่มันก็ได้พิสูจน์แล้วว่า มันช่วยผมจำและทำงานได้ดีมาตลอดหลายปีที่ผ่านมา และแม้กระทั่งบล็อกนี้เองก็เขียนอยู่บน Notion เป็น First draft เช่นกัน\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/working-how-to-work/Screenshot-2566-03-12-at-08.34.23_hu_7aecd951f02a2f2.webp\"\n       srcset=\"/working-how-to-work/Screenshot-2566-03-12-at-08.34.23_hu_975a449d5a19373a.webp 480w, /working-how-to-work/Screenshot-2566-03-12-at-08.34.23_hu_f03eabaf0bc5925d.webp 960w, /working-how-to-work/Screenshot-2566-03-12-at-08.34.23_hu_7aecd951f02a2f2.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"852\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003ch2 id=\"first-version\"\u003eFirst Version\u003c/h2\u003e\n\u003cp\u003eต้องบอกก่อนว่าก่อนหน้าจะมาอยู่บนนี้เป็นยุคที่ผม Hybrid อยู่บน Notion + Physical Notebook มาก่อน แต่ปัญหาหลักที่เจอคือ พอมันต้องแยกสองโลก ชีวิตจะเริ่มหาของยากขึ้นเรื่อยๆ ถึงแม้ผมจะเคยเชื่อว่าเราควรจะอยู่ในโลก Physical แต่ด้วยธรรมชาติของงาน Software ต้องอยู่บนคอมพิวเตอร์เกือบตลอด ต้องเก็บลิ้งค์หรือ Code snippet มันเลยทำให้ไม่สามารถไปใช้สมุดได้เต็มตัว จนถึงจุดนึงผมยอมแพ้แล้วย้ายกระบวนการในสมุดมาอยู่ใน Notion ทั้งหมด\u003c/p\u003e\n\u003cp\u003eด้วยความที่ทีมที่ผมทำงานด้วยยังอยู่บนรอบ Sprint เพราะฉะนั้นการแบ่ง Section หลักๆ จะยังเป็น Sprint based อยู่ แต่จะมี Highlight ว่าวันไหนเป็นวันหยุดด้วยการเปลี่ยนวันเป็นสีแดงไว้ด้วย แต่ก็จะมีความใช้ practices ของ Bullet Journaling อยู่คือเขียนวันของทั้งเดือนลงมาเลยทั้งหมดในหน้าเดียว วิธีนี้ช่วยให้เห็นภาพรวมของทั้งเดือนว่ามันมี Event อะไรบ้าง แล้วสิ่งที่ Notion มาช่วยเติมเต็มการทำ bullet journaling คือการที่เราสามารถ Merge ตัว Monthly Log กับ Daily Log เข้าด้วยกันได้แบบแนบเนียนมาก โดยการใช้ Toggle List ครับ\u003c/p\u003e","title":"Working how to work"},{"content":"จุดเริ่มต้นของบล็อกนี้มันมาจากรูปข้างบนครับ มันเป็นประโยคที่แฟนผมถามวันนั้นแล้วทำให้ผมคิดอะไรได้บางอย่าง คือต้องบอกว่าผมเป็นคนที่มีงานอดิเรกผ่านมา แล้วผ่านไปในชีวิตเยอะมาก ลองไล่ๆ ดูเอาเฉพาะไม่กี่ปีมานี้ตั้งแต่ Skateboard, Flight Sim, Racing Sim, Keyboard, PC Building, เรื่อยมาจนถึง Car Detailing คือมันเยอะมาก แล้วพอมามองย้อนดูดีๆ ผมสังเกตุเห็นรูปแบบของการเรียนรู้ของตัวเองชัดมาก เดี๋ยวผมจะค่อยๆ เล่าให้ฟัง\nPassion มันบังคับกันไม่ได้ จั่วหัวอย่างแรกเลยวิธีนี้ใช้กับเรื่องที่เป็นความอยากจาก External Factor ไม่ได้ หรืออย่างน้อยก็สำหรับผมนะ ความอยากจาก External Factor ยกตัวอย่างเช่น จะไปสอบ Something หรือเป็นสิ่งที่คนอื่นที่ไม่ใช่ตัวเราเองสั่งมาเช่น “พี่อยากได้ … ไปดูมาให้หน่อย” อะไรแบบนี้เป็นต้น\nสิ่งหนึ่งที่ผมสังเกตุเห็นได้ชัดจากประสบการณ์ตัวเองคือ ของที่เราจะเรียนรู้ได้ยาวนานอย่างไม่เหน็ดเหนื่อย มันต้องเป็นของที่ผุดขึ้นมาจากความอยากรู้ อยากทำด้วยตัวเองจริงๆ ยกตัวอย่างเช่น “ผมอยากให้รถของผมมันดูเงาเหมือนใหม่อยู่ตลอดเวลา” หรือ “ผมอยากจะทำ Kickflip ให้ได้ซักครั้ง” ความอยากที่ชัดเจนจากภายในตัวเองแบบนี้มันจะโผล่มาแว็บๆ ตลอดเวลาครับ\nสิ่งที่มันต่างจาก “ความอยาก” อื่นๆ คือมันกลับมาในใจมากกว่าหนึ่งครั้ง บางทีมันเกิดจากความอยากทำแต่จังหวะ มันไม่ได้ แล้วพอเหมือนจังหวะมันจะมาอีกแล้วมันกลับมาอีกรอบ แสดงว่า “ความอยาก” นั้นมันมีความแข็งแรงพอที่จะไปต่อละ\nรู้ว่าเราชอบเรียนแบบไหน ผมเป็นคนเกลียดการอ่านหนังสือสอบครับ ผมนับครั้งในชีวิตได้เลยว่าผมอ่านหนังสือก่อนสอบแบบจริงๆ จังๆ กี่ครั้ง หลายครั้งในชีวิตผมจะลงเองด้วยการเล่นเกมในคืนก่อนสอบ แล้วไปอ่านเอาหน้าห้องเอา แต่ผมค้นพบมานานแล้วว่าผมชอบโมเม้นตอนกำลังเรียนอยู่มากสุด แล้วผมจำไม่ได้แล้วว่าผมได้ยินประโยคนี้มาจากใคร แต่มันยึดติดเป็นหลักชีวิตผมมานานมากว่า “ถ้าตลอดทั้งเทอมไม่ตั้งใจเรียน แล้วมาตั้งใจอ่านหนังสือแค่วันก่อนสอบ มันจะมีประโยชน์อะไร” (disclaimer: ผมก็ไม่ได้ตั้งใจเรียนตลอดหรอก แต่ผมสนุกตอนเรียนเยอะอยู่)\nพอเรารู้ตัวแบบนี้แล้ว ผมก็พาตัวเองไปอยู่ในโลกของเรื่องที่จะเรียนรู้แบบอัตโนมัติเลยครับ ซึ่งบางครั้งมันก็ตามมาติดๆ จากตัวที่จุดประกายความอยากเราแต่แรก ต้องขอบคุณการจัดหมวดหมู่ของห้องสมุดตั้งแต่สมัยเรียนเรื่อยมาจนถึง Recommendation system ของ Youtube เลยที่ทำให้เรื่องเดียวกันมันโผล่มาเติมเต็มตลอด ซึ่งบางครั้งมันก็คือจุดเดียวกับที่จุดประกายความอยากรู้มาตั้งแต่แรกนั่นแหละ ยกตัวอย่างเช่นคลิปข้างล่างใน Youtube น่าจะเป็นคลิปล้างรถคลิปแรกๆ ที่ผมดู หลังจากนั้นมันก็พาเพื่อนมาเพียบเลยในหมวด Auto Detailing\nถ้าถามว่าแล้วเราจะรู้ได้ยังไงว่านี่เป็นวิธีเรียนรู้แบบที่เราชอบ คำตอบคือ ถ้ามันเป็นอะไรที่เราทำได้ตลอด ทำโดยที่ไม่รู้จักเหน็ดเหนื่อย ทำตั้งแต่ตื่นมาจนนอน ทำโดยที่ไม่รู้สึกตัวว่ากำลังทำอยู่ เราอินอยู่กับเรื่องที่เราสนใจมากจนเราลืมไปแล้วว่าเรากำลังศึกษามันอยู่ นั่นแหละครับคือคำตอบ\nThe learn-practice-validate loop\nLearn - Practice - Validate Loop ถ้าใครรู้สึกคุ้นๆ มันคือ loop เดียวกับ Lean เลยครับ โดยแบ่ง Stage การเรียนรู้ของเราเป็น 3 stage หลักๆ\nLearn — เป็น stage ที่เรากำลังหาคำตอบให้กับตัวเองว่าเราไม่รู้อะไรอยู่ แล้วก็หาทางเติมเต็มมัน Practice — พอรู้สึกว่ามีเครื่องมือครบมือละ พอจะมีความรู้ละก็ได้เวลาลองของจริง Validate — หลายครั้งพอลองเสร็จก็จะรู้สึกขัดๆ ก็กลับไปลองเทียบกับสิ่งที่รู้มาว่าพลาดอะไรไป แต่ถามว่า ตอนที่กำลังอินกับเรื่องอะไรอยู่นี่คิดถึง loop อะไรแบบนี้มั้ย ก็ไม่นะครับ แต่มันออกมาแบบธรรมชาติเลย ไม่ค่อยได้คิดถึงหรอกครับ มันจะมาของมันเองเดี่ยวผมยกตัวอย่างให้ฟังจากการล้างรถเองครั้งแรก\nStage ของการล้างรถ\nLearn ตอนผมรู้ตัวแล้วว่าผมอยากล้างรถแต่ผมไม่รู้เลยว่าต้องทำยังไงบ้าง ต้องใช้อะไรบ้างก็ค่อยๆ สะสมความรู้ไปเรื่อยๆ จนรู้ Stage ออกมาเป็นภาพข้างบน นี่ยังไม่นับ Practice หลายอย่างเช่น อย่า Swirl ให้เช็ดแบบ Straight direction หรือ Two bucket method หรือการเลือกใช้ brush กับแต่ละส่วน ผมบอกได้เลยว่าตอน Learn นี่แหละสนุกมาก เพราะความเป็นไปได้มันไม่มีที่สิ้นสุดมาก\nPractice อันนี้อยากโน๊ตไว้นิดนึงว่า บางครั้งเวลาผมอินกับอะไร ผมก็ไม่มาถึง Stage นี้เพราะแค่ Learn อย่างเดียวก็สนุกแล้ว หรือติดขัดเรื่องงบประมาณ แต่ถ้าเป็นเรื่องล้างรถมันมาถึงตรงนี้ได้ไวเพราะของครบเร็ว แต่ทุกครั้งเลยตั้งแต่พยายามทำ Ollie ครั้งแรกๆ, เขียนโค้ดครั้งแรกในภาษาใหม่หรือทำโฟมล้างรถครั้งแรก มันจะไม่ราบรื่นเหมือนที่เราเรียนมา ตรงนี้เอาจริงๆ ก็เป็นจุดที่สนุกมากที่เราต้องแก้ปัญหาเฉพาะหน้าที่หลายครั้ง “มันไม่ง่ายเหมือนที่ดูมาเลย” แต่ก็พยายามพาตัวเองไปจนจบให้ได้\nValidate ต่อจากขั้นลอง มันจะมีหลายครั้งที่มันจะเอ๊ะ อะไรบางอย่างติดในใจ อะไรที่ในหัวข้อที่แล้วคือ “มันไม่ง่ายแบบที่คิด” แล้วผมก็พยายามมาวนดูสิ่งที่เราเรียนใหม่ เทียบกับสิ่งที่เราทำว่าพลาดอะไรไป ความสนุกของขั้นนี้คือ บางครั้งเราก็ทำพลาดอะไรโง่ๆ ไปไม่รู้ตัวเช่น ปัดเท้าเบาไปตอนกระโดดขึ้นไป Ollie หรือใช้เวลาล้างรถนานเกินไปจนน้ำเริ่มแห้งก่อนเช็ดละ ไอของที่คาใจพวกนี้พอเรา Practice ครั้งถัดๆ ไปมันจะดีขึ้นนะ\nจริงๆ validate มีอีก aspect นึงที่ผมใช้บ่อยคือ Show your work ครับ ต้องบอกว่ามันจะเหมือนขี้อวดหน่อยๆ แต่เวลาอวดแล้วเราจะได้ฟีดแบคกลับมาด้วย ซึ่งอันนี้แหละมีค่ามาก\nรถผมเงามากครับ อวดๆ\nทำสิ่งเล็กๆ เพื่อเป้าหมายที่ยิ่งใหญ่ เคยได้ยิน Snowball effect มั้ยครับ มันคือการที่เราทำอะไรเล็กๆ หลายๆ อย่างเพื่อพุ่งเป้าไปที่เป้าหมายที่ใหญ่กว่า เหมือนกับก้อนหิมะที่ค่อยๆ กลิ้งลงจากภูเข้าแล้วเก็บหิมะระหว่างทางให้ตัวเองใหญ่ขึ้นเรื่อยๆ พอถึงตีนเขาก็กลายเป็นหิมะก้อนใหญ่ที่พร้อมซัดหน้าคนที่ขวางทาง ผิดๆ จริงๆ มีอีก analogy นึงที่คนใช้กันเยอะคือ Momentum ครับ ตราบใดที่เรายังรู้สึกว่ามี progress อยู่ แล้วเรา keep progressing ต่อไปเราก็ค่อยๆ ใกล้เป้าหมายใหญ่เราเอง\n2 analogy ที่ผมยกตัวอย่างมาเพื่อที่จะบอกว่า ถ้าเราตั้งใจจะรู้ทุกอย่างให้ได้ตั้งแต่แรกเลย มันเหนื่อยครับ แต่ถ้าเราค่อยๆ Breakdown มันออกมาหลังจากเราเริ่มจะ “รู้ว่าเราไม่รู้อะไร” มันจะช่วยให้เราค่อยๆ สนุกกับ Progression ที่เพิ่มขึ้นเอง ถามว่าผมรู้มั้ยว่าล้างรถเนี่ยมันต้องมีขั้นตอนเยอะขนาดนั้นแต่แรก ก็ไม่ ผมรู้แค่ว่าเอาน้ำมาเช็ดๆ ก็น่าจะใหม่แล้ว แต่พอเห็นภาพกว้างว่าเออมันมีขั้นตอนอยู่นะ ก็ค่อยๆ แบ่งตัวเองไปดูทีละเรื่อง ดูว่าจะล้างล้อมันทำไงนะ, จะทำโฟมทำไงนะ, จะเช็ดกระจกยังไงนะ พอเป้าย่อยๆ มันโดนเก็บเราจะรู้สึกเองว่าเป้าใหญ่มันค่อยๆ เป็นไปได้มากขึ้นเรื่อยๆ ตามมาด้วย\nถ้าไม่สนุกแล้วก็เลิก ไปทำอย่างอื่นเถอะ อย่างสุดท้ายที่อยากจะพูดถึงคือ เวลาเรามีจำกัดครับถ้าอะไรที่ทำแล้วมันไม่รู้สึกสนุกแล้วก็เลิกทำเถอะ แล้วไปทำอย่างอื่น เหมือนอ่านหนังสือแล้วรู้สึกว่าเล่มนี้อ่านไม่เข้า อ่านไม่มันเลย ก็เลิกอ่านเถอะ โลกนี้ยังมีอย่างอื่นให้ทำอีกเยอะ ดีกว่าเสียเวลาทำในสิ่งที่ไม่อยากทำครับ และสำคัญที่สุดในหลายๆ ครั้งมันไม่ได้แปลว่าเราล้มเหลวครับ\nประมาณนี้ครับ ขอย้ำอีกครั้งว่าเรื่องที่เราอยากรู้มันบังคับกันไม่ได้ แต่ถ้าเราเจอมันแล้วก็ go with the flow ครับ สิ่งสำคัญที่สุดคือ เรายังสนุกกับมันอยู่รึเปล่า ถ้าไม่สนุกแล้วก็ไปทำอย่างอื่นเถอะครับ ก็ประมาณนี้ขอให้สนุกกับการเรียนรู้ครับ\n","permalink":"https://yothinix-com.pages.dev/amateur-method/","summary":"\u003cp\u003eจุดเริ่มต้นของบล็อกนี้มันมาจากรูปข้างบนครับ มันเป็นประโยคที่แฟนผมถามวันนั้นแล้วทำให้ผมคิดอะไรได้บางอย่าง คือต้องบอกว่าผมเป็นคนที่มีงานอดิเรกผ่านมา แล้วผ่านไปในชีวิตเยอะมาก ลองไล่ๆ ดูเอาเฉพาะไม่กี่ปีมานี้ตั้งแต่ Skateboard, Flight Sim, Racing Sim, Keyboard, PC Building, เรื่อยมาจนถึง Car Detailing คือมันเยอะมาก แล้วพอมามองย้อนดูดีๆ ผมสังเกตุเห็นรูปแบบของการเรียนรู้ของตัวเองชัดมาก เดี๋ยวผมจะค่อยๆ เล่าให้ฟัง\u003c/p\u003e\n\u003ch2 id=\"passion-มนบงคบกนไมได\"\u003ePassion มันบังคับกันไม่ได้\u003c/h2\u003e\n\u003cp\u003eจั่วหัวอย่างแรกเลยวิธีนี้ใช้กับเรื่องที่เป็นความอยากจาก External Factor ไม่ได้ หรืออย่างน้อยก็สำหรับผมนะ ความอยากจาก External Factor ยกตัวอย่างเช่น จะไปสอบ Something หรือเป็นสิ่งที่คนอื่นที่ไม่ใช่ตัวเราเองสั่งมาเช่น “พี่อยากได้ … ไปดูมาให้หน่อย” อะไรแบบนี้เป็นต้น\u003c/p\u003e\n\u003cp\u003eสิ่งหนึ่งที่ผมสังเกตุเห็นได้ชัดจากประสบการณ์ตัวเองคือ ของที่เราจะเรียนรู้ได้ยาวนานอย่างไม่เหน็ดเหนื่อย มันต้องเป็นของที่ผุดขึ้นมาจากความอยากรู้ อยากทำด้วยตัวเองจริงๆ ยกตัวอย่างเช่น “ผมอยากให้รถของผมมันดูเงาเหมือนใหม่อยู่ตลอดเวลา” หรือ “ผมอยากจะทำ Kickflip ให้ได้ซักครั้ง” ความอยากที่ชัดเจนจากภายในตัวเองแบบนี้มันจะโผล่มาแว็บๆ ตลอดเวลาครับ\u003c/p\u003e\n\u003cp\u003eสิ่งที่มันต่างจาก “ความอยาก” อื่นๆ คือมันกลับมาในใจมากกว่าหนึ่งครั้ง บางทีมันเกิดจากความอยากทำแต่จังหวะ มันไม่ได้ แล้วพอเหมือนจังหวะมันจะมาอีกแล้วมันกลับมาอีกรอบ แสดงว่า “ความอยาก” นั้นมันมีความแข็งแรงพอที่จะไปต่อละ\u003c/p\u003e\n\u003ch2 id=\"รวาเราชอบเรยนแบบไหน\"\u003eรู้ว่าเราชอบเรียนแบบไหน\u003c/h2\u003e\n\u003cp\u003eผมเป็นคนเกลียดการอ่านหนังสือสอบครับ ผมนับครั้งในชีวิตได้เลยว่าผมอ่านหนังสือก่อนสอบแบบจริงๆ จังๆ กี่ครั้ง หลายครั้งในชีวิตผมจะลงเองด้วยการเล่นเกมในคืนก่อนสอบ แล้วไปอ่านเอาหน้าห้องเอา แต่ผมค้นพบมานานแล้วว่าผมชอบโมเม้นตอนกำลังเรียนอยู่มากสุด แล้วผมจำไม่ได้แล้วว่าผมได้ยินประโยคนี้มาจากใคร แต่มันยึดติดเป็นหลักชีวิตผมมานานมากว่า “\u003cem\u003eถ้าตลอดทั้งเทอมไม่ตั้งใจเรียน แล้วมาตั้งใจอ่านหนังสือแค่วันก่อนสอบ มันจะมีประโยชน์อะไร\u003c/em\u003e” (disclaimer: ผมก็ไม่ได้ตั้งใจเรียนตลอดหรอก แต่ผมสนุกตอนเรียนเยอะอยู่)\u003c/p\u003e","title":"มือสมัครเล่นเมธอด"},{"content":"ผมคิดมาหลายวันละ ว่าถ้าปีแรกของอายุขึ้นต้นด้วยเลข 3 นี่ผมไม่ได้เขียน Year In Review ผมคงจะเสียใจมาก เพราะมันมีเรื่องราว เยอะจัดๆ แล้วหนักด้วย ถึงแม้ตอนนี้จะผ่านมาได้เกือบหมดละ แต่พอมองย้อนไปนี่มันไม่ง่ายเลย\n👨‍🦳💰 Dad \u0026amp; Dept เรื่องแรกที่ใหญ่ที่สุดปีนี้เลยคือพ่อป่วยติดเชื้อที่ขาตอนช่วงต้นปี ทั้งๆ ที่เป็นคนออกกำลังกายทุกวัน หนักจนถึงระดับที่ว่าตอนหนักๆ นี่ไม่พูดไม่จาเลย แล้วยังจำได้แม่นว่าเป็นช่วงเวลาเดียวกันกับที่โควิดระบาดหนักสุดในปีนี้ ทำให้ช่วงสัปดาห์แรกที่พ่อป่วยไม่ได้เจอหน้าเลย แม่ก็ไปเจอหน้าไม่ได้เพราะโรงพยาบาลปิดวอร์ดหมด เป็นสาม สี่วันที่ระทึกมากตอนนั้นเพราะกลัวทั้งอาการที่พ่อป่วย กลัวโควิดมาแทรกซ้อนอีก แต่พ่อก็เอาตัวรอดมาได้พร้อมกับเรื่องเล่าความหิวน้ำที่ยังเล่าจนถึงทุกวันนี้ แต่ก็ยังไม่จบเพราะต้องพักฟื้นอีกเกือบๆ เดือนนึง ถึงได้กลับบ้าน ซึ่งตอนนี้ก็กลับมาพูดเสียงดังปกติ พร้อมกับน้ำหนักที่ลดไปจากจุดสูงสุดไปเกือบ 15 กิโล\nในช่วงเวลาเดียวกันกับที่พ่อป่วย ตอนนั้นเลยได้รู้ความจริงอีกอย่างว่าที่บ้านที่หนี้สินอยู่จำนวนนึง อาจจะไม่ได้เยอะมากถ้าเทียบกับคนอื่น แต่ก็ไม่สามารถจ่ายให้หมดได้ภายในวันเดียว ซึ่งพอพ่อป่วยระบบที่พ่อคอยดูแลหนี้ตัวนี้มันรวนหมดเลย เพราะพ่อไปจ่ายเองไม่ได้ เลยทำให้ที่บ้านต้องช่วยกันจัดการกัน หลังจากตั้งสติได้แล้วก็คือต้องงัดทุกความรู้กับประสบการณ์ในการจัดการหนี้ตัวเองมาก่อนหน้านี้มาใช้ทั้งหมด จนได้แผนที่ตอนแรกถูก Projection ไว้ว่าหนี้ตัวนี้เนี่ย น่าจะหมดกลางๆ ปี 2025 แต่ Inspect \u0026amp; Adapt แผนมาเรื่อยๆ จนบอกได้เต็มปากเลยว่าหนี้ 95% ถูกจัดการหมดแล้วในปี 2022 นี้\nขอเล่าเรื่องหนี้ต่ออีกนิดนึงละกัน คือจริงๆ มันไม่ยากแต่เราต้อง Proactive กับมันแทนที่จะ Reactive ตอนบิลแจ้งหนี้มันมาถึงบ้านแล้วตลอดปีที่ผ่านมา Principle หลักๆ ที่ใช้ตอนจัดการจะมีอยู่ 3 อย่างเลยคือ cash flow ถ้าไม่มี cash flow เอาไปจ่ายหนี้อย่างเดียวจนหมดไม่มีตังค์กินข้าวทำอย่างอื่น เราจะไม่มีแรงไปทำงานหาเงินต่อเลย อันนี้คืออย่างแรก อย่างที่สองคือ Visualize คือตอนแรกที่เรารู้ว่ามีเรื่องหนี้นี้ไม่มีใครเห็นภาพเลยว่ามันมากแค่ไหน แล้วมาจากตรงไหนบ้าง พอเรา Projection ออกมาได้มันเลยทำให้วางแผนได้ง่ายขึ้นมากว่าจะจัดการยังไง อย่างสุดท้ายพูดไปข้างบนแล้วคือ Inspect \u0026amp; Adapt ทุกๆ 2-3 เดือนในปีนี้ผมกลับมารีวิวแผนที่วางไว้ แล้วแทบจะปรับใหม่ทุกครั้ง หลังเราเข้าใจธรรมชาติของหนี้หลายๆ อย่างมากขึ้นเลยทำให้ค่อยๆ ร่นเวลาเข้ามาได้จนหมดไปส่วนใหญ่ในปีนี้\n👨‍💻 Lost \u0026amp; Found ช่วงต้นปีนี่ยังมีความหลงทางอยู่ว่าตัวเองต้องการอะไรกันแน่ รู้แค่ว่าทำ Backend อยู่ไปเรื่อยๆ ไม่ได้ละ เลยพยายามหาลู่ทางออกนอกประเทศ พร้อมๆ กับเรียน Java Bootcamp ที่สุดท้ายเรียนไม่จบเพราะมีเรื่องข้างบนเข้ามาพอดี ในช่วงที่ in the void พอดีนี้ก็มีคุณภูมิใจนี่แหละทักมา เลยจับพลัดจับพลูได้มาทำงานอยู่ที่ปัจจุบัน\nในช่วงเวลาตอนต้นปีถึงกลางปีนั้นมีความทรงจำดีๆ หลายเรื่องอยู่หลังจากผ่านวิกฤติพ่อที่เล่าข้างบนมาได้ ไม่ว่าจะเป็น How to ลาออก ยังไงไม่ให้บ้านบึ้มหรือ👷📚 เล่าให้ฟัง: ย้ายสายจาก Software Engineer มาเป็น Data Engineer สามเดือนแรกหรือหลังจากนั้นถึงแม้ว่าจะไม่ได้เขียนเล่าออกมาเป็นบล็อกเท่าไร แต่บอกได้เลยว่างานที่ทำอยู่นี่มีอะไรให้ทำอีกเยอะมาก แล้วทุกวันที่ทำงานยังรู้สึกว่าเป็น A whole new world อยู่เพราะโลกหมุนไปเร็วเหลือเกิน แต่ถ้าจะมีอะไรที่อยากพูดถึงเรื่องงานมี 3 เรื่อง\nขอบคุณภาพจากคุณ Teera ด้วยคับ\nอย่างแรกคือ Dagster รู้สึกโชคดีอย่างนึงที่เข้ามาใช้งานจริงๆ ในจังหวะที่ Dagster กำลัง move แบบก้าวกระโดดมากๆ พอดี เลยได้เห็นจังหวะกำลังเปลี่ยนจากโลกเดิมจาก solid, pipeline ไปเป็น ops, jobs เรื่อยมาจนถึงยุค Software-defined Assets ที่ได้มีโอกาสไปแชร์เรื่องนี้ที่งาน Grill The Data กับใน Internal Engineering Training ด้วย\nอย่างที่สองคือไม่เคยคิดเลยว่าตัวเองจะทำงานบน Jupyter Notebook ได้และชอบด้วย ก่อนจะมาทำงานที่นี่ถึงแม้จะมีโอกาสได้ใช้บ้าง แต่ก็ยังเชื่อว่าเขียนเป็น Python file ง่ายกว่าเป็น comfort zone กว่า จนเริ่มมาอยู่กับ Notebook จริงๆ จังๆ ช่วงครึ่งปีหลังเลยได้รู้จักมันมากขึ้นว่า มันไม่ใช่แค่เขียนโค้ดได้ แต่มันเอาไว้ experiment, share knowledge, ทำเป็น artifact ฯลฯ คือมันทำอะไรได้เยอะมากๆ คล้ายๆ กับตอนใช้ emacs org mode แต่เข้าถึงง่ายกว่ามาก\nอย่างที่สามคือโลก SQL เป็นอะไรที่ลึกล้ำมากและเปิดโลกมากๆ ตลอดปีที่ผ่านมาทำให้รู้เลยว่าตอนเขียน application วิธีที่ใช้ SQL อยู่คือน้อยกว่าคนทำงานทาง Data มากๆ แต่ก็รู้สึกหลายอย่างเหมือนกันว่า Practices จากฝั่งการทำ application ก็ไหลๆ มาหางานทาง Data ในแนวเดียวกันเหมือนกัน สังเกตุจากสิ่งที่ dbt ทำหรือ tooling ต่างๆ ที่เกิดขึ้นมาในโลก SQL แต่ถึง SQL จะ unified ขนาดไหนความรู้ในการ tuning database ที่สะสมกันมาเป็นสิบๆ ปีก็ยังใช้ได้เสมอ ทั้งการ optimize query plan, การทำ indexing ฯลฯ ของพวกนี้รู้ไว้ยังหากินได้อีกยาวไกลครับ\n🏡 🚙 F A M I L Y เอาจริงๆ ถ้าไม่มีกะตั๊กนี่จินตนาการไม่ออกเลยว่าชีวิตจะเป็นยังไง ตั้งแต่ที่ต้องกลับมาคอยดูแลพ่อกับแม่ตอนต้นปี ก็มีกะตั๊กบินกลับมาอยู่บุรีรัมย์ด้วย เลยได้ลองใช้ชีวิตอยู่บ้านแทนคอนโดที่อยู่มาหลายปี เลยเริ่มเข้าใจว่าชีวิตแบบนี้มันก็สบายอีกแบบนะ\nแล้วภาพแบบนี้ก็เริ่มชัดขึ้นเรื่อยๆ จนกระทั่งสัญญาคอนโดใกล้จะหมด แล้วคุยไปเหมือนจะต่อสั้นๆ ไม่ได้เลยได้ตระเวนหาบ้านเช่าในกรุงเทพฯ ตลอดเดือนตุลาคม ซึ่งจริงๆ เรื่องเล่าตอนหาบ้านกับคุณกะตั๊กนี่บอกได้เลยว่ามันจัดๆ ทั้งไปเจอบ้านที่ติดยัน ทิ้งใบปริญญาไว้แบบหลอนๆ หรือบ้านที่เราเลือก แต่เจ้าของบ้านไม่เลือกเรา ฯลฯ แล้วก็มีคุณธอร์นี่แหละ ที่ได้ฟังเรื่องนี้แบบเต็มๆ จนชาบูเนื้อร้านลับที่เชียงใหม่ของคุณธอร์อร่อยขึ้นอีกเป็นกอง\nThat small home office we build from the ground up\nซึ่งสุดท้ายแล้วเดือนพฤศจิกายนก็เลยได้บอกลาการเป็นชาวเมือง มาเป็นชาวชานเมืองอยู่บ้าน ทำอาหารกินเองเต็มตัว แล้วทำให้ค้นพบว่าทุกๆ อย่างดูกว้างขวางขึ้นแล้วก็เงียบขึ้นแบบรู้สึกได้ อีกอย่างนึงที่ได้มาจากการออกมาอยู่บ้านแทนคอนโด คือการได้ทำห้องทำงานเองนี่แหละ ซึ่งสนุกนะแล้วมันเปลี่ยนวิธีใช้ชีวิตไปเลย เพราะการไปทำงานคือการไปเข้าห้องทำงานจริงๆ แยกออกมาจากการใช้ชีวิตในบ้านส่วนอื่นๆ ทำให้เวลาพักผ่อนมัน fully charge กว่าสมัยก่อนมาก\nแต่การอยู่นอกเมืองก็มี cost ที่ต้องแลกมาคือต้องมีรถ ช่วงแรกๆ ที่อยู่นี่ ลำบากสัสๆ เรียก Grab ไม่ได้เลยจะมีแต่ LINE Man Taxi นี่แหละที่พอเรียกติดบ้าง แล้วการแค่ไปตลาดห่างจากบ้านไปแค่ 3km ที่อาจจะแวบไปแปปเดียว แต่ใช้เวลาตั้งครึ่ง ชม. เพราะกว่า Taxi จะผ่านมาซักคันนี่รอจนเมื่อย ซึ่งสุดท้ายแล้วมันทนไม่ไหวแล้วต้องใช้รถจริงๆ เลยไม่รอละ Civic FE ที่จองไว้แบบไม่รู้อนาคต เลยกระโดดไปหา Toyota Corolla Cross GR Sport ได้เป็นรถแฝดกับรถพี่เหน่งเฉย พร้อมกับความสามารถในการโม้ได้ว่าเลขตัวถังรถเราสวยมาก ฮ่าๆ\nน้องแพนแพน\nปล.จริงๆ ปีนี้ติดโควิดด้วย จริงๆ เข้าโรงพยาบาลก็บ่อยนะ แต่โควิดนี่คือโหดมาก หนาวสั่นไปหลายวัน เจ็บคอไปหลายวันกว่าจะหาย แต่กะตั๊กก็ยังแข็งแกร่งอยู่ด้วยกันทุกวัน แต่ก็ยังไม่ติดจนถึงทุกวันนี้\nบันทึกไว้ว่าครั้งหนึ่งในชีวิตเราเคยสองขีด\n","permalink":"https://yothinix-com.pages.dev/2022/","summary":"\u003cp\u003eผมคิดมาหลายวันละ ว่าถ้าปีแรกของอายุขึ้นต้นด้วยเลข 3 นี่ผมไม่ได้เขียน Year In Review ผมคงจะเสียใจมาก เพราะมันมีเรื่องราว เยอะจัดๆ แล้วหนักด้วย ถึงแม้ตอนนี้จะผ่านมาได้เกือบหมดละ แต่พอมองย้อนไปนี่มันไม่ง่ายเลย\u003c/p\u003e\n\u003ch2 id=\"-dad--dept\"\u003e👨‍🦳💰 Dad \u0026amp; Dept\u003c/h2\u003e\n\u003cp\u003eเรื่องแรกที่ใหญ่ที่สุดปีนี้เลยคือพ่อป่วยติดเชื้อที่ขาตอนช่วงต้นปี ทั้งๆ ที่เป็นคนออกกำลังกายทุกวัน หนักจนถึงระดับที่ว่าตอนหนักๆ นี่ไม่พูดไม่จาเลย แล้วยังจำได้แม่นว่าเป็นช่วงเวลาเดียวกันกับที่โควิดระบาดหนักสุดในปีนี้ ทำให้ช่วงสัปดาห์แรกที่พ่อป่วยไม่ได้เจอหน้าเลย แม่ก็ไปเจอหน้าไม่ได้เพราะโรงพยาบาลปิดวอร์ดหมด เป็นสาม สี่วันที่ระทึกมากตอนนั้นเพราะกลัวทั้งอาการที่พ่อป่วย กลัวโควิดมาแทรกซ้อนอีก แต่พ่อก็เอาตัวรอดมาได้พร้อมกับเรื่องเล่าความหิวน้ำที่ยังเล่าจนถึงทุกวันนี้ แต่ก็ยังไม่จบเพราะต้องพักฟื้นอีกเกือบๆ เดือนนึง ถึงได้กลับบ้าน ซึ่งตอนนี้ก็กลับมาพูดเสียงดังปกติ พร้อมกับน้ำหนักที่ลดไปจากจุดสูงสุดไปเกือบ 15 กิโล\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/2022/Screenshot-2565-12-31-at-09.58.04_hu_67a9ba2a11d474e6.webp\"\n       srcset=\"/2022/Screenshot-2565-12-31-at-09.58.04_hu_71a49e5a6ddff751.webp 480w, /2022/Screenshot-2565-12-31-at-09.58.04_hu_609f9e2c45359a9e.webp 960w, /2022/Screenshot-2565-12-31-at-09.58.04_hu_67a9ba2a11d474e6.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"630\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eในช่วงเวลาเดียวกันกับที่พ่อป่วย ตอนนั้นเลยได้รู้ความจริงอีกอย่างว่าที่บ้านที่หนี้สินอยู่จำนวนนึง อาจจะไม่ได้เยอะมากถ้าเทียบกับคนอื่น แต่ก็ไม่สามารถจ่ายให้หมดได้ภายในวันเดียว ซึ่งพอพ่อป่วยระบบที่พ่อคอยดูแลหนี้ตัวนี้มันรวนหมดเลย เพราะพ่อไปจ่ายเองไม่ได้ เลยทำให้ที่บ้านต้องช่วยกันจัดการกัน หลังจากตั้งสติได้แล้วก็คือต้องงัดทุกความรู้กับประสบการณ์ในการจัดการหนี้ตัวเองมาก่อนหน้านี้มาใช้ทั้งหมด จนได้แผนที่ตอนแรกถูก Projection ไว้ว่าหนี้ตัวนี้เนี่ย น่าจะหมดกลางๆ ปี 2025 แต่ Inspect \u0026amp; Adapt แผนมาเรื่อยๆ จนบอกได้เต็มปากเลยว่าหนี้ 95% ถูกจัดการหมดแล้วในปี 2022 นี้\u003c/p\u003e\n\u003cp\u003eขอเล่าเรื่องหนี้ต่ออีกนิดนึงละกัน คือจริงๆ มันไม่ยากแต่เราต้อง Proactive กับมันแทนที่จะ Reactive ตอนบิลแจ้งหนี้มันมาถึงบ้านแล้วตลอดปีที่ผ่านมา Principle หลักๆ ที่ใช้ตอนจัดการจะมีอยู่ 3 อย่างเลยคือ cash flow ถ้าไม่มี cash flow เอาไปจ่ายหนี้อย่างเดียวจนหมดไม่มีตังค์กินข้าวทำอย่างอื่น เราจะไม่มีแรงไปทำงานหาเงินต่อเลย อันนี้คืออย่างแรก อย่างที่สองคือ Visualize คือตอนแรกที่เรารู้ว่ามีเรื่องหนี้นี้ไม่มีใครเห็นภาพเลยว่ามันมากแค่ไหน แล้วมาจากตรงไหนบ้าง พอเรา Projection ออกมาได้มันเลยทำให้วางแผนได้ง่ายขึ้นมากว่าจะจัดการยังไง อย่างสุดท้ายพูดไปข้างบนแล้วคือ Inspect \u0026amp; Adapt ทุกๆ 2-3 เดือนในปีนี้ผมกลับมารีวิวแผนที่วางไว้ แล้วแทบจะปรับใหม่ทุกครั้ง หลังเราเข้าใจธรรมชาติของหนี้หลายๆ อย่างมากขึ้นเลยทำให้ค่อยๆ ร่นเวลาเข้ามาได้จนหมดไปส่วนใหญ่ในปีนี้\u003c/p\u003e","title":"2022"},{"content":"ตอนนี้น่าจะถึงเวลาอันสมควรละที่จะมาอัพเดทโพสในหมวดคีย์บอร์ดอีกครั้งหลังจากหายไปนานมาปีกว่า จนถึงตอนนี้ก็ใช้คีย์บอร์ดมา 4 layout physical layout + 3 logical layout โพสนี้เลยจะมาเล่าให้ฟังว่าปรับตัวเองให้ใช้คีย์บอร์ดที่มีอยู่แต่ละตัวได้ยังไง สลับไปสลับมาโดยที่ไม่บ้าไปซะก่อน โดยจะเริ่มจากตัวที่มีปุ่มเยอะที่สุดไล่ลงไปหาปุ่มน้อยที่สุดครับ\nErgodox EZ ในบรรดาทุกตัวในรอบหนึ่งปี ตัวนี้เป็นคีย์บอร์ดที่มีวิวัฒนาการ layout เป็นหลักมาอย่างต่อเนื่อง เรียกได้ว่าปรับไปใช้โปรแกรมไหนก็มาปรับตรงนี้ตามเดี๋ยวเราค่อยๆ ดูไปทีละ layer เลย\nlayer 0 - Dvorak ด้วยความที่ layout ภาษาอังกฤษหลังผมเป็น Dvorak เลยบังคับโดยปริยายว่า layer แรกต้องเป็น Dvorak ก่อนหน้านี้เคยใช้ Dvorak เป็น layer หลังๆ แต่ค้นพบว่ามันจำกัดการใช้งานคีย์บอร์ดลงเยอะมาก ถ้าเป็น layer รองๆ ซึ่งนอกจากจะใช้เป็น Dvorak ในตัว Base แล้ว Modifier ข้างๆ ก็ปรับตาม Ergodox เช่นกัน เพราะปุ่มน้อยลงตรงขอบๆ แต่มากขึ้นในส่วนที่เป็นนิ้วโป้ง ซึ่งพวก - = [ ] ที่ Dvorak เอาไว้ทางขวาบนผมก็แมพมาไว้ในแถวล่างสุด แล้วใช้นิ้วโป้งกดแทนครับ\nเริ่มจากทางซ้ายบนผมแมพ Undo (Cmd + Z) เอาไว้ตรงที่คีย์บอร์ดอื่นๆ จะเป็น ESC หรือ grave ascent ซึ่งมีประโยชน์เพราะแทนที่จะต้องกดสองปุ่มก็เหลือปุ่มเดียวแทน ปุ่มถัดมาก็จะเป็น alt/option ปุ่มแรกแทน tab เพราะ tab ไปอยู่ตรงนิ้วโป้งขวาแล้ว ถัดลงมาที่ปกติจะเป็น Caplock ซึ่งไม่มีประโยชน์สำหรับผมเลยเปลี่ยนเป็น Ctrl เวลากด hold และเป็น ESC เวลากดปกติ ซึ่งสองปุ่มนี้พอมันย้ายมาอยู่ใกล้ๆ home row มันทำให้ผมไม่ต้องยกมือขึ้นมาบ่อยๆ เวลากด ESC เพื่อออกจาก Insert mode ของ Vim หรือทั้ง Ctrl, Alt ต่างก็เป็น lead key ใน Emacs ก็ช่วยลดอาการปวดนิ้วก้อยหรือ Emacs Pinky ไปได้บ้าง เรื่อยไปถึง Magnet ก็ช่วยให้กด lead key ที่ต้องกดทั้ง Ctrl + Alt ในการจัดระเบียบ Window ด้วย\nในส่วนของตรงกลางจะเป็นปุ่ม Screen capture ซึ่งพอเราต้องใช้ทั้งแบบ area และแบบ full screen เลยแมพแยกไปเลยจะได้ใช้ง่ายๆ ถัดมาทางซ้ายจะเป็น Copy/Paste ซึ่งจุดประสงค์เดียวกับ Undo คือไม่ต้องกด Lead key ให้มันจบๆ ไป ส่วนทางขวาจะเป็นปุ่มไว้ปรับไป Layer 3 ที่เป็น QWERTY ซึ่งปกติจะใช้ร่วมกับปุ่ม lang ซึ่งจริงๆ เป็น Macro ที่กด Win + Space ให้ไว้เปลี่ยนภาษาครับ จะเห็นว่าความลำบากนิดหน่อย (แต่ตอนนี้ชินแล้ว) คือไม่ใช่แค่เปลี่ยนภาษาแล้วจะพิมพ์ได้เลย แต่ต้องเปลี่ยน layout กลับมาเป็น QWERTY ด้วย\nจุดเด่นของ Ergodox คือ Thumb Cluster ครับ ซึ่งทำให้นิ้วโป้งที่เคยเอาไว้แค่กด Space ง่อยๆ ทำอะไรได้มากขึ้น เช่นนิ้วโป้งซ้ายที่มีสองปุ่ม แต่ผมทำได้ 4 อย่างเลยคือ ซ้ายสุดถ้ากดจะเป็น Space แต่ถ้ากด hold จะเป็น Command/Win ส่วนซ้ายรองถ้ากดจะเป็น Backspace แต่ถ้ากด hold จะเป็น alt/option ปุ่มที่สอง ในส่วนของนิ้วโป้งขวาผมไม่ซับซ้อนมากเลยเป็น Tab, Enter ตามลำดับ ส่วนปุ่มม่วงๆ ข้างบนก็แมพคีย์ลัดไว้เปิดโปรแกรมเช่น raycast, 1password แทนที่จะกดหลายปุ่มก็กดปุ่มพวกนี้ปุ่มเดียวแทน\nทางขวาไม่มีอะไรพิเศษครับ แค่มีปุ่มที่ปกติจะเป็น Enter ให้เป็น Window แทนเวลา hold เพราะบางโปรแกรมใช้ Win + Space ซึ่งพอมันอยู่ด้วยกันตรงนิ้วโป้งซ้ายก็ไม่รู้จะกดยังไงเลยต้องมีแบคอัพไว้อีกปุ่มครับ\nย้อนกลับมาตรงกลางหน่อยคือเวลาเราวางมือตรง Home row นิ้วก้อยผมจะมีหน้าที่เป็น Layer toggle เวลากด Hold เพิ่มมาอีกทั้งสองข้างเลย โดยก้อยซ้ายจะ switch ไป Layer1 ส่วนก้อยขวาจะไป Layer2 ครับ\nlayer 1 - Symbols พอผมกดนิ้วก้อยซ้ายตัวคีย์บอร์ดจะ switch มา layer1 ให้จนกว่าผมจะปล่อยซึ่งหลักๆ ใน layer นี้จะเป็นสิ่งที่ Ergodox เซตมาให้แต่แรกคือพวก F1 → F12 จะไล่เรียงกันไปตามแถวบนสุด แต่ use case หลักๆ ผมใน layer นี้จะเอาไว้กดคีย์ที่ใช้บ่อยๆ เวลาเขียนโปรแกรมครับ\nโดยคีย์ที่ใช้บ่อยสุดในการเขียนโปรแกรมคือวงเล็บทุกแบบ ซึ่งจะอยู่ในระยะนิ้วกลางกับชี้ซ้ายในขณะที่นิ้วก้อยซ้ายกด hold อยู่ ทำให้เวลาผมเขียนวงเล็บไม่ต้องยกมือไปสุดขอบขวาบนเหมือนชาว Dvorak ปกติครับ รวมไปถึงพวกใช้บ่อยๆ รองลงมาใน Shell ทั้ง Tilde, Pipe, Grave Ascent ต่างก็อยู่ในนี้ให้กดง่ายๆ ด้วย นอกจากนี้จะเห็นว่าใน Layer นี้ผมแมพปุ่ม Copy/Paste ไว้เหมือนกัน แต่ใน Layer1 นี้จะเป็นของ Windows แทนครับซึ่งเป็นคีย์คนละคีย์กับ Mac\nส่วนทางขวาด้วยความที่ผมใช้ IDE อย่าง PyCharm, IntelliJ ด้วยแล้วมันจะมีคีย์ที่กดบ่อยๆ อย่างเช่น Code Generator, Refactor, Switch to Terminal, Goto Implementation ก็เอามาแมพไว้เป็นคีย์ใน home row เลยจะกดก็ไม่ต้องยกมือออก ส่วนคีย์ที่ใช้บ่อยรองลงมาเช่นพวกสั่ง Run, Debug ก็เอาไว้ข้างบนกับล่างแทน ซึ่งมีทั้งแบบกด Cmd กับ Ctrl แยกกัน\nlayer 2 - Navigations ถ้ายังจำกันได้จาก layer 0 ผมจะใช้นิ้วก้อยขวาในการกดไป layer 2 ซึ่งจะพามาหา navigation นี่แหละครับ ซึ่งจะมีพวกลูกศรที่ถ้าใครเป็นชาว Vim ก็จะอ๋อทันทีว่า นี่คือการแมพ navigation แบบเดียวกับที่ Vim ใช้เลย นอกจากนั้นแล้วแป้นซ้าย ถ้าขี้เกียจยกมือ ยังสามารถทำตัวเป็นเมาส์แทนได้ด้วยครับ\nส่วน G,C,H,T เป็นคีย์ที่ผมเอาไว้กดคู่กับปุ่ม Alt + Left Ctrl ซึ่งถ้าจำได้มันเป็น Lead key ของ Magnet ทำให้ผมสามารถจัด Window แบบแบ่ง 4 หน้าจอได้ง่ายๆ เลยครับ\nlayer 3 - QWERTY ในส่วนของ Layer 3 จะเป็น QWERTY ไว้ใช้ในกรณีที่ผมจะพิมพ์ภาษาไทยหรืออะไรที่ต้องการ QWERTY จริงๆ ครับโดยจะสลับมาผ่านปุ่ม toggle layer 3 ตรงกลางๆ ที่เป็นลายๆ จาก layer 0 ซึ่งประโยชน์ของ Layer นี้มีแค่นี้จริงๆ ครับ 555\nlayer 4 - FPS Layer นี้จุดประสงค์ตามตัวครับคือเอาไว้เล่นเกม ซึ่งน่าจะใกล้เคียงกับคีย์บอร์ดปกติที่สุดละ ซึ่งถามว่าแล้วทำไมต้องทำแยกมาจาก layer 3 - QWERTY ต้องบอกว่าพวกปุ่ม Modifier ใน Layer นี้ถ้าจะสังเกตุดีๆ จะใกล้เคียงกับคีย์บอร์ดคนทั่วไปมากที่สุดละครับ ซึ่งมันก็คือคีย์บอร์ดที่เกมมันออกแบบมาให้ใช้เล่นเกมนั่นเอง ในขณะที่ QWERTY จะยังใช้ความสามารถของปุ่มที่แมพไว้ใน Layer 0 หลายปุ่มอยู่ครับ\nlayer 5 - Steno อันนี้แถมเฉยๆ ด้วยความที่คีย์บอร์ดที่เป็น QMK Based firmware จะรองรับ Steno mode ด้วยทำให้ผมเซต layer นี้เอาไว้ใช้เล่น Steno ที่ทำให้เราพิมพ์คำผ่านการกดคอร์ดได้ครับ แต่ต้องบอกว่าหลังจากใช้แล้วมันไม่สบายมากๆ เพราะคีย์บอร์ดปกติเราปุ่มมันจะสูงๆ แล้วการกดคอร์ดมันต้องวางนิ้วไว้ระหว่างกลางของสองปุ่มเช่น T- K- พอต้องกดคอร์ดที่ต้องใช้สองปุ่มเลยเจ็บมากครับ ผมเลยแนะนำว่าถ้าอยากลอง Steno จริงๆ ไปซื้อคีย์บอร์ด steno หรือ low profile มาลองจะเจ็บนิ้วน้อยกว่าครับ ซึ่งผมก็มีอีกอันคือ Georgi keyboard ที่เป็น low profile ไว้ฝึก Steno โดยเฉพาะครับ\nd60lite — 60% HHKB จริงๆ มาเขียนบล็อกนี้เพราะว่าเพิ่งได้ตัวนี้มานี่แหละ แล้วหลังจากใช้งานมาอาทิตย์กว่าๆ รู้สึกว่ามันได้ Custom มาอยู่ในจุดที่ใช้ได้ใกล้เคียงกับตอนใช้ Ergodox บ้างแล้ว แต่ก็ยังต้องพัฒนาต่อไปเรื่อยๆ เดี๋ยวค่อยๆ ดูทีละ layer โดยต้องบอกว่าพื้นฐานของแต่ละ layer ก็จะมาจากที่เคยใช้ใน Ergodox นีแหละครับ\nlayer 0 - Dvorak โดยใน Layer 0 นี้พื้นฐานจะเป็น Dvorak เหมือนกันจากประสบการณ์ที่ได้มาจาก Ergodox ที่ layer แรกจะมีความสามารถมากที่สุด แต่ก็จะเสียความสามารถของ Ergodox ไปที่ทำให้นิ้วโป้งเรามีความสามารถเยอะกลับกลายเป็นกด Space เหงาๆ เหมือนเดิมแทน แล้วยกภาระให้กับ Modifier ไปกองกันทางขวาแบบใกล้เคียงคีย์บอร์ดปกติแทน\nในส่วนของปุ่ม Tab, Caplock ถ้าเทียบกับคีย์บอร์ดปกติตัวนี้จะคล้ายๆ กับ Ergodox โดยปุ่ม Tab จะกลายเป็น Tab ถ้ากดแต่ถ้า hold จะเป็น Alt ส่วน Caplock จะเป็น Esc ถ้ากดและ Ctrl ถ้า hold ต่อมาส่วนของ home row เรายังใช้ประโยชน์จากนิ้วก้อยในการ switch ไป layer1 ตอน hold เหมือนเดิม\nส่วนที่ Tricky แต่ก็โชคดีคือการที่ HHKB layout ย้ายปุ่ม backspace ลงมาทำให้ผมมีปุ่มขวาบนที่ไม่มีในคีย์บอร์ดปกติเพิ่มขึ้นมา ทำให้ตรงจุดนี้ผมแมพ Macro เป็น Win + Space หรือปุ่มเปลี่ยนภาษาครับ ซึ่งจะใช้คู่กับปุ่ม TO(3) ซึ่งเป็นปุ่ม Switch ไป layer 3 ในการสลับระหว่าง EN(Dvorak) → TH(QWERTY) ได้ใกล้เคียงกับ Ergodox เลย\nซึ่งก็จะเหลือปุ่ม MO(1) กับ MO(2) ที่ไม่มีในคีย์บอร์ดปกติเหมือนกัน ผมเลยเอาไว้ทำงานพิเศษคือ switch ไป layer ตามตัวเลขมัน\nlayer 1 - Symbols + Navigations อาศัย Practice จาก Ergodox เหมือนกัน แต่แทนที่จะแยก symbol, navigation layer ก็จับมันมารวมกันเลย นั่นหมายความว่า layer switch ที่ใช้นิ้วก้อยใน layer 0 คือชี้มาที่ layer นี้แทนหมด\nด้วยความที่ปุ่มตรงกลางๆ ที่ Ergodox มันหายไปเลยต้องที่ของ Curry Bracket เดิมให้กับ Copy/Paste แทน แล้วย้ายไปกด Curry Bracket กับตัวล่างแทนผ่านการกด Shift ทางขวาร่วมด้วย แต่ด้วยความที่ Curry Bracket ยังเจอไม่บ่อย (ยกเว้นเขียน template เลยยังไม่ปวดใจมากตอนนี้)\nlayer 3 - QWERTY ตัว layer 3 ไม่มีอะไรมากมันคือ QWERTY ปกติเลย และปุ่มต่างๆ ใกล้เคียงกับ layer 0 มากยกเว้นเปลี่ยน TO(0) แทนเพื่อให้มันพากลับ layer 0\nDrop x OLKB Planck Keyboard — 40% Ortholinear ด้วยความที่เคยระเบิด Planck keyboard ไปรอบนึงแล้ว เพราะพยายามจะ Custom layout นี่แหละพอได้อีกตัวมาเลยใช้ง่ายๆ ละแทนที่จะ Custom ให้เหมือนตัวบนๆ ที่ผ่านมา ตัวนี้คือ มีอะไรให้ใช้ก็ใช้เลย ซึ่งด้วยความที่ Planck มี Dvorak Layer ให้ switch มาอยู่แล้ว พอปรับตัวมาจาก Ergodox ก็สามารถทำงานได้เลย ตัวปุ่มอาจจะเรียงแปลกๆ บ้างแต่ก็สลับมาใช้ QWERTY ได้แบบพิมพ์ไทยถูๆ ไถๆ ได้\nsrc: https://www.reddit.com/r/olkb/comments/oll0oi/create_you_own_planckpreonic_keymap/\nปัญหาหลักๆ ของการที่ปรับมาใช้ Planck คือการที่ต้องกด layer เพื่อจะกดแถวตัวเลขได้นี่แหละ เป็นอะไรที่พอสลับใหม่ทุกครั้ง ก็ต้องเริ่มทำความคุ้นเคยใหม่ทุกครั้ง ยังไม่ชินซักที\nก็ประมาณนี้ครับ จริงๆ ถ้ามามองย้อนดูจุดเริ่มต้นที่เริ่ม Custom layer เยอะขนาดนี้แรกสุดเลย ไม่ใช่เพราะ Ergodox แต่เป็นตอนที่วางแผนจะมาใช้ Planck แล้วต้องพยายามจัดการตัวเองให้อยู่ใน 40% layout ให้ได้ เลยทำให้เริ่มมาศึกษาการใช้ Layer จนออกมาแบบที่เล่ามาข้างบนนั่นแหละครับ\nส่วนใครใช้ Layer ยังไงอยู่มาแชร์กันได้ฮะ ผมอยากเห็นมากเผื่อจะเอาไปปรับใช้เองด้วย สำหรับบล็อกนี้ก็ประมาณนี้ครับ\n","permalink":"https://yothinix-com.pages.dev/custom-keyboard-layout-story/","summary":"\u003cp\u003eตอนนี้น่าจะถึงเวลาอันสมควรละที่จะมาอัพเดทโพสในหมวดคีย์บอร์ดอีกครั้งหลังจากหายไปนานมาปีกว่า จนถึงตอนนี้ก็ใช้คีย์บอร์ดมา 4 layout physical layout + 3 logical layout โพสนี้เลยจะมาเล่าให้ฟังว่าปรับตัวเองให้ใช้คีย์บอร์ดที่มีอยู่แต่ละตัวได้ยังไง สลับไปสลับมาโดยที่ไม่บ้าไปซะก่อน โดยจะเริ่มจากตัวที่มีปุ่มเยอะที่สุดไล่ลงไปหาปุ่มน้อยที่สุดครับ\u003c/p\u003e\n\u003ch2 id=\"ergodox-ez\"\u003eErgodox EZ\u003c/h2\u003e\n\u003cp\u003eในบรรดาทุกตัวในรอบหนึ่งปี ตัวนี้เป็นคีย์บอร์ดที่มีวิวัฒนาการ layout เป็นหลักมาอย่างต่อเนื่อง เรียกได้ว่าปรับไปใช้โปรแกรมไหนก็มาปรับตรงนี้ตามเดี๋ยวเราค่อยๆ ดูไปทีละ layer เลย\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/custom-keyboard-layout-story/ergodox0_hu_c0de1f5cf5ef0732.webp\"\n       srcset=\"/custom-keyboard-layout-story/ergodox0_hu_d256498c03d51f42.webp 480w, /custom-keyboard-layout-story/ergodox0_hu_fe33074e685e070b.webp 960w, /custom-keyboard-layout-story/ergodox0_hu_c0de1f5cf5ef0732.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"832\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003ch3 id=\"layer-0---dvorak\"\u003elayer 0 - Dvorak\u003c/h3\u003e\n\u003cp\u003eด้วยความที่ layout ภาษาอังกฤษหลังผมเป็น Dvorak เลยบังคับโดยปริยายว่า layer แรกต้องเป็น Dvorak ก่อนหน้านี้เคยใช้ Dvorak เป็น layer หลังๆ แต่ค้นพบว่ามันจำกัดการใช้งานคีย์บอร์ดลงเยอะมาก ถ้าเป็น layer รองๆ ซึ่งนอกจากจะใช้เป็น Dvorak ในตัว Base แล้ว Modifier ข้างๆ ก็ปรับตาม Ergodox เช่นกัน เพราะปุ่มน้อยลงตรงขอบๆ แต่มากขึ้นในส่วนที่เป็นนิ้วโป้ง ซึ่งพวก - = [ ] ที่ Dvorak เอาไว้ทางขวาบนผมก็แมพมาไว้ในแถวล่างสุด แล้วใช้นิ้วโป้งกดแทนครับ\u003c/p\u003e","title":"ผม custom layout คีย์บอร์ดยังไงบ้าง"},{"content":"โพสนี้เหมือนเป็นภาคต่อจาก ลาออกยังไงไม่ให้บ้านบึ้ม ครับคือกระบวนการต่างๆ มันเริ่มตั้งแต่เรายังทำงานในที่เก่าอยู่ โพสนี้เลยจะมาเล่าให้ฟังคร่าวๆ ว่าก่อนจะเริ่มงาน Data Engineer และที่ผ่านมาสามเดือนนี้ผมผ่านอะไรมาบ้าง พร้อมวิธีการเอาตัวรอดในแบบของผมเองละกัน\n💡 Disclaimer: ความเห็นต่างๆ ในโพสนี้เป็นความคิดเห็นส่วนตัว ไม่ได้เกี่ยวข้องกับบริษัทที่ผมทำงานอยู่ปัจจุบันแต่อย่างใดครับ\nก่อนเริ่มงาน 1 เดือน จากตอนที่แล้วผมบอกไว้ว่ามันจะมีช่วงที่เรา lower your light ซึ่งเป็นเวลาที่ดีที่สุดที่เราจะเตรียมตัวกับงานใหม่ จังหวะนี้เป็นช่วงที่ผมหาข้อมูลงานใหม่ให้มากที่สุดครับ ซึ่งจากเท่าที่คุยตอนสัมภาษณ์ผมรู้แค่ว่า Tooling หลักคือ Dagster ช่วงแรกๆ ผมเลยดู Dagster เป็นหลักเลยซึ่ง ณ จุดนี้ถ้ามองย้อนไปผมบอกเลยว่า Tutorial ของ Dagster มันเป็นกับดักครับ 555 คือมันดูเหมือนจะเข้าใจง่าย job, ops, เขียนเทสได้ อะไรก็ว่าไป แต่ของจริงมันอยู่ใน Concept กับตัวอย่างใน GitHub ของ Dagster เองครับ อันนั้นคือถ้ากระโดดต่อมาจาก Tutorial ก็จะมีความช็อคน้ำหน่อยๆ แต่เดี๋ยว Dagster ผมมาเล่าต่อในอนาคต มีอีกหลายเรื่องเลยให้เล่าครับ\nนอกจาก Dagster แล้วผมต้องขุดความทรงจำว่าเพื่อนร่วมงานผมในอนาคต (ซึ่งเป็นเพื่อนร่วมงานในปัจจุบัน) เค้าทำอะไรมาบ้าง ซึ่งโชคดีมากที่เค้าเคยเล่าไว้ใน LINE Developers Podcast ไว้ถึง 2 ตอนเลย เพราะใน Podcast นี้แนะนำไว้ชัดเจนเลยว่า เราควรจะรู้จัก Hadoop ecosystem นะ ซึ่งผมไต่ไปหลายบล็อกมาก ช่วงนั้นเพื่อจะอัพเดทความรู้ Hadoop ตัวเองที่ถูกแช่ไว้ตั้งแต่ปี 2013 ซึ่งในบรรดาบล็อกทั้งหมดที่ผมไล่อ่านมา ผมประทับใจบล็อก Good Old Days Hadoop นี้มากครับซึ่งเล่าประวัติ Hadoop ได้เห็นภาพมาก รวมถึงพูดถึง YARN, Spark ไว้นิดหน่อยด้วย ซึ่งตอนนั้นผมยังจับภาพไม่ได้เลยว่ามันเกี่ยวกันยังไง\n💡 “Software Engineer ทุกคนเราอ่ะเป็น Data Engineer อยู่แล้ว เพียงแค่ความเข้มข้นในการเข้าไปจัดการข้อมูลของเรามันต่างกัน”\n- ผมชอบประโยคนี้ของเพื่อนร่วมงานในอนาคตผมมาก\nนอกจาก Podcast ข้างบนผมโชคดีอย่างนึงที่ผมพอจะรู้จักเพื่อนร่วมงานในอนาคตผมอีกคน ซึ่งผมก็ถามไปตรงๆ เลยว่าผมควรดูอะไรก่อนบ้างก็ได้รู้จัก Apache Spark มาซึ่งพอได้ยินแบบนั้นปั๊ป ผมกดเรียนคอร์ส Batch Data Pipeline with Spark แบบไม่ลังเลเลย แล้ว Live Project ของ Manning ดีอย่างนึงคือไม่ใช่แค่ก็อปโค้ดแปะแล้วรันได้ แต่จะคล้ายทำงานจริงๆ มากที่บอกว่า เราอยากได้แบบนี้แหละ แล้วก็มี resource guide ให้คร่าวๆ แต่เราต้องไปเปิด Doc API ของ Spark เองว่าจะใช้ฟังก์ชั่นอะไร มาทำให้งาน Ingestion, Cleaning data เป็นไปแบบที่เราต้องการ แล้วนอกจากนั้นยังมีพวก Tips อะไรแทรกอยู่ด้วยเหมือนเรามีเพื่อนร่วมงานระดับโลกคอยคุยกับเราผ่านตัวหนังสือไปอีก\nแต่ยังไม่ทันได้เรียนจนจบคอร์สข้างบนผมก็มีโอกาสเจอเพื่อนร่วมงานในอนาคตผมอีกคน ซึ่งผมก็ถามแบบตรงๆ เหมือนเดิม แต่คำตอบที่ได้มาต่างกันคือผมน่าจะลองไปดู Apache Hive กับ Presto ดูซึ่งด้วยความที่เวลาเหลืออีกไม่กี่วันจะเริ่มงานละ ผมเลยลองดูหนังสือ Learn Hive in 1 Day ดู ซึ่งสำหรับคนจะไปดูนะฮะ ข้ามหนังสือเล่มนี้ไปเลยครับ เพราะผมซึ่งไปดู Spark มาก่อนหน้านี้บอกเลยว่าเล่มนี้ไม่ได้ให้ Concept อะไรใหม่ๆ กับเราเลย (แถมพิมพ์ผิดเยอะมากแบบน่ารำคาญ (น่าจะอ่าน Amazon Review ก่อน TT)) แต่อย่างน้อยก็เสียเวลาไม่ถึงวัน\nในส่วนของ Presto เราจะไม่สามารถเข้าใจมันได้เลย ถ้าเราไม่เข้าใจ Hive มาก่อนเพราะ Presto ยังต้องพึ่ง component สำคัญของ Hive อย่าง Metastore ในการทำความรู้จักกับข้อมูลที่เก็บอยู่ ซึ่งตอนเรารู้จัก Hive ใหม่ๆ เราคิดว่าว้าวแล้วนะ ที่มันมา Optimize ให้การทำ MPP บน HDFS มันง่ายขึ้นกว่าสมัย Map Reduce มากแล้วการเอา Compute ไปอยู่ใกล้ๆ Disk นี่ก็ว้าวแล้ว แต่พอรู้จัก Presto ก็จะว้าวไปอีกเพราะมัน Optimize ขึ้นมาอีกขั้นเพื่อ ad-hoc query โดยมาทำงานใน Memory แทน ซึ่งผมรู้ทั้งหมดนี่ผ่านลิ้งค์ต่อไปนี้ครับ [1][2][3][4]\nจริงๆ ยังมี Source อีกหลายแหล่งไม่ว่าจะเป็น Data Engineer Cafe, Data Engineer Zoomcamp ฯลฯ ที่เป็นที่พึ่งให้ผมเตรียมตัวด้วย ซึ่งพอถึงจุดนี้เหลือเวลาไม่กี่วันหลังเริ่มงานผมบอกเลยว่าในหัวตอนนี้ทุกอย่างที่ผมเล่ามามันตีกันไปหมดมากๆ ซึ่งถ้าใครเคยมองมาวงการ Data Science/Engineering ก็น่าจะรู้สึกไม่ต่างจากผมว่าทุกอย่างมันถาโถม มันเยอะมากจนไม่รู้จะเริ่มจากตรงไหนดีแล้วในใจก็ยังรู้ว่ามันยังมี Unknow อีกมากที่ต้องไปเจอหน้างานถึงจะรู้ว่าอะไร\nเดือนแรก พอเข้ามาเดือนแรก ผมได้รับการบอกกล่าวเลยว่า Data Engineer ที่นี่น่าจะไม่เหมือนที่อื่นนะตาม Data Maturity ขององค์กร ซึ่งแรกๆ ผมก็ไม่ค่อยได้ยินใครพูดที่ไหนเรื่องนี้นอกจากกับเพื่อนร่วมงานผม จนกระทั่งเพิ่งเห็นพี่ทอยเขียนบล็อกนี้ เลยรู้ซึ้งว่าวิธีการแยกแบบนี้มันมาจากหนังสือเล่มนี้ ซึ่งพอมามองย้อนกลับไป เอ่อจริง เพราะตั้งแต่เดือนแรกไม่ใช่ผมกระโดดไปทำ Data pipeline เลย แต่ไปทำความเข้าใจว่า pyhive มันทำงานยังไงกับ Hive, Spark, Presto จนไปรู้จัก Thrift server ที่ทำงานอยู่ข้างหลัง รวมถึงไปทำความรู้จักกับ Hadoop ecosystem อีกครั้ง (แบบมีคนคุยด้วย)\nแต่ก็ใช่ว่าจะไม่มีงาน Data pipeline เลย ซึ่งงานหนึ่งที่ Data Engineer ทุกคนที่นี่ได้ทำคือการ Migrate Dagster abstraction ของ data pipeline ให้มาใช้ตัวใหม่ครับ ซึ่งผมบอกเลยว่า การไปดูกับการมานั่งทำงานกับ production ready pipeline มันต่างกันเยอะมากครับ นอกจากจะต้องไปค้น Docs ว่า Abstraction ใหม่มัน migrate ยังไงบ้างตั้งแต่ระดับ repository, schedule เรื่อยไปจนถึง resource แล้ว support system, tooling, หรือ workflow ต่างๆ ก็ต้องไปทำความรู้จักกับมันเช่น GitOps, Earthly, หรือแม้กระทั่ง SQL ที่เหมือนจะรู้จักอยู่แล้ว แต่พอเห็นวิธีการเขียนแบบ CTEs รวมถึง Dialect ของแต่ละ Query engine ที่ต้องทำงานด้วยก็ตระหนักได้ว่าเรายังไม่รู้อะไรเลย\nโชคดีที่เดือนแรกผมมีวันหยุดยาวอยู่กลางเดือนหลังจากไปทำงานได้อาทิตย์เดียว เลยเป็นช่วงเวลาที่กลับมาตั้งสติได้ดีมาก ซึ่งตัวช่วยทำให้ผมกลับมาเห็นภาพหลายๆ อย่างชัดขึ้นเป็นภาพข้างบน ต้องขอบคุณหนังสือ Designing Cloud Data Platforms เลยครับ เล่มนี้ช่วยดึงสติให้ผมกลับมาเห็น Data Platform ใน Mental model ได้ชัดเหมือนสมัยยังเป็น Software Engineer แล้วมองว่าแต่ละ components ของแอพมันคืออะไร มาทำหน้าที่อะไร ซึ่ง 3 บทแรกจะพาไป รู้จัก Data Platform ก่อน ส่วนบทที่เหลือในหนังสือจะพาไปเจาะลึกทั้ง tools, techniques ของแต่ละ component ตั้งแต่ Ingestion, Processing เรื่อยไปถึง Data Access ซึ่งส่วนตัวผมยังอ่านไม่จบ ถ้าจบแล้วก็น่าจะมีโอกาสมาเล่าให้ฟังกันในบล็อกนี้ครับ เรียกได้ว่าคัมภีร์คู่ใจผมเลยมาจนถึงทุกวันนี้\nเดือนที่สอง งานในช่วงเดือนที่สองมีความแตกต่างขึ้นไปนิดนึง เพราะพอเริ่มเข้าโปรเจ็คจะมีงานในส่วนของ Data Modeling กับ Data Exploration เพิ่มเข้ามา ในส่วนของ Data Modeling เรียกได้ว่าอาศัยประสบการณ์ Backend Engineer มาเอาตัวรอดไปได้ครับในการออกแบบ Schema ของ Data ที่เรา Provide ให้ Consumer ใช้ยังไงให้ตอบโจทย์ requirements และ Maintain ได้สบายไปพร้อมๆ กัน แต่ส่วน Data Exploration นี่เรียกได้ว่าเป็นประสบการณ์ที่แปลกใหม่มาก เพราะเราต้องไปตามหา Data ที่เราต้องการมาตอบโจทย์ Business requirements ความยากนอกจากต้องไปตะลุยทุ่ง Documents, Wiki เพื่อหา Data ที่ต้องการแล้ว ก็ต้องมา Verify ต่อว่าตอบโจทย์ที่เราต้องการจริงๆ มั้ยนะ หรือติด limitation อะไรด้วยรึเปล่า ซึ่งกินพลังชีวิตหนักมากทั้ง 2 ส่วนที่ผมว่าเลยครับ\nในส่วนของ Data pipeline ที่ยังต้องดูแลอยู่แต่พอเริ่มจะใช้ Dagster ได้อยู่มือขึ้น ก็เริ่มเห็นภาพว่าเห้ยการดูแล data pipeline อ่ะ มันไม่ต่างกับการดูแล Software อื่นๆ เลยนะ เพราะตัว pipeline มันมีอายุของมัน มีการ extend มีการ upgrade ฯลฯ เพราะฉะนั้น practices ต่างๆ ของ Software Engineering ในการสร้าง Maintainable software เข้ามาช่วยเยอะมากตอนนี้ครับ\nเดือนที่สาม พอเข้าเดือนที่สามมีโอกาสได้ไปแตะๆ งาน POC Platform บ้าง ผมมีโอกาสไปลอง POC ในส่วนเล็กๆ ที่ decoupling compute engine interface ออกมาโดยใช้ Apache Livy เป็นพื้นฐาน ซึ่งไองาน POC เล็กๆ ที่ว่าพาผมไปรู้จัก Hadoop, YARN, Spark เยอะขึ้นมากกว่าตอนที่ดูเองก่อนหน้านี้เยอะมากว่ามันคุยกันยังไงกว่าจะได้ processing, storage layer ใน Data Platform ขึ้นมาซักตัว\nอีกสิ่งหนึ่งที่ค่อยๆ เห็นภาพชัดขึ้นแล้วค่อนข้างเป็น Pitfall หนึ่งของคนใช้งาน Dagster คือ Ops ไม่ใช่ function ซึ่งตอนแรกที่ได้ยินมาผมยังไม่เข้าใจ Dagster มากประโยคนี้เลยยังอยู่ในใจอยู่ แต่พอขึ้น data pipeline เส้นที่สองแล้วเริ่มรู้สึกว่าทำไมต้องมาทำซ้ำด้วยนะ เท่านั้นแหละเหมือนคนตรัสรู้เลย แล้วเส้นแบ่งมันนิดเดียวมากคือ Ops เราต้อง general ระดับนึงแล้วใช้ abstraction ของ Dagster ในการจัดการ input, output หรือ behavior ของ Ops นั้นแทน แล้วพอมองโลก Dagster ผ่านเลนส์นี้เท่านั้นแหละ ผมเห็นโอกาสเต็มไปหมดเลยครับและผมมั่นใจว่าพวกที่ทำ Tooling ในวงการ data ก็เห็นสิ่งนี้เหมือนกันมานานก่อนผมมาก เราเลยได้เห็น ความร่วมมือของ tool หลายๆ อย่างกับ Dagster เช่น Dagster x dbt, Dagster x Airbyte อะไรแบบนี้เป็นต้นครับ\nคำแนะนำจากประสบการณ์ต๊อกต๋อยนี้ ประมาณนี้ครับประสบการณ์สามเดือนผม ยังคิดว่าตัวเองประสบการณ์น้อยมากในงาน Data Engineering และยังมีอะไรให้เรียนรู้เพิ่มอยู่เรื่อยๆ อีกในทุกๆ วัน แต่ถ้าพอมามองย้อนกลับไปถ้าจะมีอะไรแนะนำคนที่อยากจะย้ายมาทำงานสาย Data Engineering ผมพอจะแนะนำจากประสบการณ์น้อยนิดของผมได้ตามนี้เลยครับ\nอย่างแรกเลย มันมีความต่างเยอะมากระหว่างคนที่เป็น Consumer ของ Platform กับคนที่สร้าง Platform ผมเข้าใจภาพนี้ชัดมากถ้ามองย้อนไปตอนผมรู้จัก Spark ใหม่ๆ แล้วก็รู้สึกว่าเอ่อ มันก็ไม่ต่างจาก Pandas ที่เราคุ้นเคยมากนี่หว่า แต่พอต้องประกอบมันขึ้นมาจริงๆ แล้วโลกของ Spark นี่มันกว้างใหญ่โคตรๆ เลยครับ แค่เปลี่ยน Resource manager นี่โลกก็เปลี่ยนแล้ว เพราะฉะนั้นย้ำอีกครั้งว่า มันสำคัญมากที่เราจะต้องเข้าใจ Tooling ที่เราต้องทำงานหรือดูแลด้วยไม่ใช่แค่ใช้เป็น แต่เข้าใจเลยว่ามันทำงาน (ด้วยกัน) ได้ยังไง อย่างที่สองผมมาตกผลึกตอนต้องไปทำ Data Exploration นี่แหละครับ ด้วยความที่มันมีสิ่งที่เกิดขึ้นใหม่ๆ ในโลกของ Data ตลอดเวลา ไม่นับ Data Domain ที่เราต้องไปความเข้าใจด้วย สิ่งที่จะเกิดขึ้นตามมาคือ สิ่งที่เรารับรู้มันจะเยอะมาก จนหลายครั้งมันถาโถม วิธีการเอาตัวรอดจากตรงนี้ให้ได้คือ เราต้องจัดการความรู้ของเราเองให้เป็นครับ สามารถกลั่นความรู้ออกมาจากสิ่งที่รับรู้และต่อยอดเพื่อที่จะเข้าใจสิ่งใหม่ๆ ต่อได้ ซึ่งวิธีการที่ผมใช้หลักๆ คือจดครับและแน่นอนว่าเครื่องมือคู่ใจผมยังคงเป็น Notion ไม่ว่าใครจะชวนไปใช้ tooling ตัวไหนก็ตาม 555 อย่างสุดท้าย ผมไปดู Live ของบอย BigData RPG หลายอาทิตย์ก่อนตอนกำลังดูประกาศรับสมัครงานสาย Data แล้วผมไปสะดุดใจกับคุณสมบัตินึงในประกาศคือ Self-Driven ซึ่งตอนที่ฟังแล้วมามองย้อนกลับไป มันจริงมาก เพราะพอถึงจุดหนึ่งหลังจากเราเริ่มเห็นภาพอะไรชัดขึ้นแล้ว ด้วยความที่ทะเลของงานในสาย Data Engineering มันเยอะมาก เราต้องเป็นคนตัดสินใจเองว่าอยากจะโฟกัสเรื่องอะไร โดยที่ยัง Align กับ Goal ของงานที่ทำอยู่ ต้องรู้ว่าไม่รู้อะไร จะได้ไปเติมสิ่งที่ขาดให้มันเต็ม และต้อง สั่งตัวเองเป็นด้วย เพราะอิสระมาพร้อมกับความรับผิดชอบสูงมาก สุดท้ายถึงแม้ผมจะเพิ่งพูดเรื่อง Self-Driven ไป แต่ผมบอกเลยว่าผมผ่านมาถึงจุดนี้ไม่ได้เลย ถ้าผมไม่มีเพื่อนร่วมงานที่สุดยอดมากๆ ทุกคน ทุกบทสนทนา ทุกมุมมองต่างๆ ที่ผมได้รับการแบ่งปันมา ผมไม่รู้จะตอบแทนยังไงเลยนอกจากตั้งใจทำงานออกมาให้ดีที่สุดและหวังว่าซักวัน ผมจะได้แบ่งปันสิ่งที่ผมรู้กลับไปบ้าง\nปล.ผมชอบคำว่าต๊อกต๋อยมากเวลาได้ยินจากเพื่อนร่วมงานผม เวลาได้ยินแล้วรู้สึก Stand on the shoulder of giant มาก​ ฮ่าๆ\n","permalink":"https://yothinix-com.pages.dev/first-three-month-as-data-eng/","summary":"\u003cp\u003eโพสนี้เหมือนเป็นภาคต่อจาก \u003ca href=\"/how-to-resign/\"\u003eลาออกยังไงไม่ให้บ้านบึ้ม\u003c/a\u003e ครับคือกระบวนการต่างๆ มันเริ่มตั้งแต่เรายังทำงานในที่เก่าอยู่ โพสนี้เลยจะมาเล่าให้ฟังคร่าวๆ ว่าก่อนจะเริ่มงาน Data Engineer และที่ผ่านมาสามเดือนนี้ผมผ่านอะไรมาบ้าง พร้อมวิธีการเอาตัวรอดในแบบของผมเองละกัน\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💡 Disclaimer: ความเห็นต่างๆ ในโพสนี้เป็นความคิดเห็นส่วนตัว ไม่ได้เกี่ยวข้องกับบริษัทที่ผมทำงานอยู่ปัจจุบันแต่อย่างใดครับ\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"กอนเรมงาน-1-เดอน\"\u003eก่อนเริ่มงาน 1 เดือน\u003c/h2\u003e\n\u003cp\u003eจากตอนที่แล้วผมบอกไว้ว่ามันจะมีช่วงที่เรา lower your light ซึ่งเป็นเวลาที่ดีที่สุดที่เราจะเตรียมตัวกับงานใหม่ จังหวะนี้เป็นช่วงที่ผมหาข้อมูลงานใหม่ให้มากที่สุดครับ ซึ่งจากเท่าที่คุยตอนสัมภาษณ์ผมรู้แค่ว่า Tooling หลักคือ Dagster ช่วงแรกๆ ผมเลยดู Dagster เป็นหลักเลยซึ่ง ณ จุดนี้ถ้ามองย้อนไปผมบอกเลยว่า \u003ca href=\"https://docs.dagster.io/tutorial\"\u003eTutorial\u003c/a\u003e ของ Dagster มันเป็นกับดักครับ 555 คือมันดูเหมือนจะเข้าใจง่าย job, ops, เขียนเทสได้ อะไรก็ว่าไป แต่ของจริงมันอยู่ใน Concept กับตัวอย่างใน GitHub ของ Dagster เองครับ อันนั้นคือถ้ากระโดดต่อมาจาก Tutorial ก็จะมีความช็อคน้ำหน่อยๆ แต่เดี๋ยว Dagster ผมมาเล่าต่อในอนาคต มีอีกหลายเรื่องเลยให้เล่าครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/first-three-month-as-data-eng/Screen-20Shot-202565-06-30-20at-2007.04.41_hu_3a43fd7e47e1b1c5.webp\"\n       srcset=\"/first-three-month-as-data-eng/Screen-20Shot-202565-06-30-20at-2007.04.41_hu_3a43fd7e47e1b1c5.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"228\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eนอกจาก Dagster แล้วผมต้องขุดความทรงจำว่าเพื่อนร่วมงานผมในอนาคต (ซึ่งเป็นเพื่อนร่วมงานในปัจจุบัน) เค้าทำอะไรมาบ้าง ซึ่งโชคดีมากที่เค้าเคยเล่าไว้ใน \u003ca href=\"https://www.youtube.com/c/LINEDevelopersThailand\"\u003eLINE Developers Podcast\u003c/a\u003e ไว้ถึง 2 ตอนเลย เพราะใน Podcast นี้แนะนำไว้ชัดเจนเลยว่า เราควรจะรู้จัก Hadoop ecosystem นะ ซึ่งผมไต่ไปหลายบล็อกมาก ช่วงนั้นเพื่อจะอัพเดทความรู้ Hadoop ตัวเองที่ถูกแช่ไว้ตั้งแต่ปี 2013 ซึ่งในบรรดาบล็อกทั้งหมดที่ผมไล่อ่านมา ผมประทับใจบล็อก \u003ca href=\"https://tharid.com/posts/good-old-days-hadoop/\"\u003eGood Old Days Hadoop\u003c/a\u003e นี้มากครับซึ่งเล่าประวัติ Hadoop ได้เห็นภาพมาก รวมถึงพูดถึง YARN, Spark ไว้นิดหน่อยด้วย ซึ่งตอนนั้นผมยังจับภาพไม่ได้เลยว่ามันเกี่ยวกันยังไง\u003c/p\u003e","title":"👷📚 เล่าให้ฟัง: ย้ายสายจาก Software Engineer มาเป็น Data Engineer สามเดือนแรก"},{"content":"เห็นน้องมิว Mils Burasakorn เขียนบล็อกแล้วมีรูป #learntoday ขึ้นเลยอยากย้อนความหลังไปปี 2017 มาโม้ว่าไอเดียนี้มันเกิดขึ้นได้ไง\nย้อนไปปีนั้น #ProntoTools กลับมาเล่น Leader กันทั้งทีมเพื่อให้ทุกคนมีสิทธิกำหนดทิศทางของ Policy ต่างๆ ภายในทีมในช่วงระยะเวลาหนึ่งๆ น่าจะประมาณ 1 เดือนถ้าจำไม่ผิด แล้วตอนนั้นผมจับได้เป็น Leader คู่กับโครี่เป็นคู่แรก เลยกำหนด Policy ขึ้นมา 2-3 อย่างแล้ว apply กับทีม Pronto Tools หนึ่งในนั้นคือ #learntoday\n#learntoday เป็นไอเดียที่เอาจริงๆ ผมไม่ได้คิดขึ้นมาเองแต่แรกอันนี้ disclaimer ก่อนเลย มันเกิดจากตอนที่นั่งคุยกับโครี่อยู่แล้วอารมณ์ประมาณว่ามันน่าจะดีนะ ถ้าเรารู้สึกว่าเราได้เรียนรู้อะไรในทุกๆ วันชีวิตจะไม่น่าเบื่อเลย แล้วกว่าจะถึงวันศุกร์หรือการจะจัด sharing session กันความตื่นเต้นเวลาเราได้เรียนรู้อะไรใหม่ๆ มันจะหายไปหมดแล้ว เลยคิดว่าต้องหาอะไรที่มัน light weight กว่านั้นมาเป็นช่องทางในการแบ่งปัน เพื่อที่จะให้ทุกคนรู้สึกว่า มันไม่ใช่เรื่องยากเลยที่เราจะ share knowledge ซึ่งกันและกัน\nแล้วผมจำได้ว่าย้อนไปไม่กี่เดือนก่อนหน้านี้ผมเคยอ่านบล็อกของ Basecamp ชื่อ \u0026ldquo;What did you learn at work today?\u0026rdquo; (https://m.signalvnoise.com/what-did-you-learn-at-work-today/) ซึ่งเล่าให้ฟังว่า DHH เค้าใช้ฟีเจอร์ Automatic check-ins ที่ basecamp ยังไงบ้าง แล้วผมรู้สึกว่าเห้ยนี่มันเป็นไอเดียที่ดีมากเพราะช่องทางการสื่อสารเราเป็นแบบ async ไปเลย แม้แต่ knowledge sharing ก็ตาม\nซึ่งตอนนั้น Pronto Tools ยังไม่ได้ใช้ Basecamp (แต่หลังจากนั้นไม่นานก็ใช้นะ แล้วเราใช้ check-in กันดุเดือดมาก) แต่ใช้ Slack เป็นช่องทางสื่อสารหลักในทีมอยู่แล้ว เลยเกิดไอเดียว่าเห้ยมาสร้างห้องใหม่เป็น #learntoday ดีกว่า แล้วใครรู้อะไรใหม่ๆ สำหรับตัวเองก็พิมพ์ไว้เลย นอกจากจะเป็นประโยชน์กับตัวเองว่า เห้ยเรารู้อะไรใหม่วันนี้นะ หลายคนที่ไม่ได้ทำงานในส่วนเดียวกันมาอ่านดูก็อาจจะได้รู้ท่าใหม่ๆ โดยไม่ต้องทำงานตรงจุดนั้นเองก็ได้ ยังเอาไว้ search หาว่าอ่อเคยทำท่านั้น ท่านี้ตอนนู้นก็สามารถ search หาเจอได้\nซึ่งเอาจริงๆ ตอนคิดตอนแรก ก็ไม่ได้คิดว่าจะใช้ยืนยาวต่อกันมานานขนาดนี้ จนตามไปหลายบริษัทที่ชาว Pronto Tools แยกย้ายกันออกไปด้วย ผมก็มาเห็นอีกทีว่าอ้าวมี #learntoday กันด้วยเหรอนี่ หรืออย่างตัวผมเองที่ใช้ Practice เดียวกับมิวเลยคือมี page: Learn Today อยู่ใน Notion ตัวเอง แล้วก็เขียนไว้ตลอดถ้าได้รู้อะไรใหม่ๆ ซึ่งมันช่วยได้มากจริงๆ สำหรับผมตอนที่ self-esteem เราตกมากๆ ว่าเห้ย เราก็ได้เรียนรู้อะไรใหม่ๆ อยู่ ไม่ได้กากอย่างที่มองตัวเองนี่หว่า และมันทำให้รู้สึกว่าตัวเองยังมีค่าอยู่นะ\nสุดท้าย ผมเพิ่งมาค้นพบว่าจริงๆ ไอเดียนี้มันก็มีอีกคนคิดเหมือนกันอยู่ในวงการ Tech อยู่ ถ้าเราสังเกตุใน Twitter จะมีโพสประมาณแบบ #TIL ซึ่งแรกๆ ผมเห็นก็แบบ TIL อะไรวะ แต่พอไปหาดู อ่อมันคือ \u0026ldquo;today I learned\u0026rdquo; ซึ่งมันคือไอเดียเดียวกันเลยกับ #learntoday เลยครับ แต่ผมจะไม่เคลมว่าผมคิดก่อน เพราะอย่างที่บอกผมก็ได้ inspiration มาจาก Basecamp อีกที 555\nปล.ขอบคุณ Mils Burasakorn ที่พูดถึง #learntoday ด้วยเห็นแล้วใจฟูมากที่ยังมีคนใช้อยู่ทั้งๆ ที่ผ่านมาหลายปีแล้ว 🥹\n","permalink":"https://yothinix-com.pages.dev/learntoday/","summary":"\u003cp\u003eเห็นน้องมิว \u003ca href=\"https://www.facebook.com/mesodiarc?__cft__%5B0%5D=AZXMPFTOCKhKuTu56KT9b5dqNnfusOCCFw3VQy4kWrq3ObA78SO_saXfwUH9tZaw0i77zKl3xq6TATy-TqkZJy9XxfExF40F3wljo_bMj6sJ90t_2ZCcSDVl8jLDDBTemvk\u0026amp;__tn__=-%5DK-R\"\u003eMils Burasakorn\u003c/a\u003e เขียนบล็อกแล้วมีรูป \u003ca href=\"https://www.facebook.com/hashtag/learntoday?__eep__=6\u0026amp;__cft__%5B0%5D=AZXMPFTOCKhKuTu56KT9b5dqNnfusOCCFw3VQy4kWrq3ObA78SO_saXfwUH9tZaw0i77zKl3xq6TATy-TqkZJy9XxfExF40F3wljo_bMj6sJ90t_2ZCcSDVl8jLDDBTemvk\u0026amp;__tn__=*NK-R\"\u003e#learntoday\u003c/a\u003e ขึ้นเลยอยากย้อนความหลังไปปี 2017 มาโม้ว่าไอเดียนี้มันเกิดขึ้นได้ไง\u003c/p\u003e\n\u003cp\u003eย้อนไปปีนั้น \u003ca href=\"https://www.facebook.com/hashtag/prontotools?__eep__=6\u0026amp;__cft__%5B0%5D=AZXMPFTOCKhKuTu56KT9b5dqNnfusOCCFw3VQy4kWrq3ObA78SO_saXfwUH9tZaw0i77zKl3xq6TATy-TqkZJy9XxfExF40F3wljo_bMj6sJ90t_2ZCcSDVl8jLDDBTemvk\u0026amp;__tn__=*NK-R\"\u003e#ProntoTools\u003c/a\u003e กลับมาเล่น Leader กันทั้งทีมเพื่อให้ทุกคนมีสิทธิกำหนดทิศทางของ Policy ต่างๆ ภายในทีมในช่วงระยะเวลาหนึ่งๆ น่าจะประมาณ 1 เดือนถ้าจำไม่ผิด แล้วตอนนั้นผมจับได้เป็น Leader คู่กับโครี่เป็นคู่แรก เลยกำหนด Policy ขึ้นมา 2-3 อย่างแล้ว apply กับทีม Pronto Tools หนึ่งในนั้นคือ \u003ca href=\"https://www.facebook.com/hashtag/learntoday?__eep__=6\u0026amp;__cft__%5B0%5D=AZXMPFTOCKhKuTu56KT9b5dqNnfusOCCFw3VQy4kWrq3ObA78SO_saXfwUH9tZaw0i77zKl3xq6TATy-TqkZJy9XxfExF40F3wljo_bMj6sJ90t_2ZCcSDVl8jLDDBTemvk\u0026amp;__tn__=*NK-R\"\u003e#learntoday\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.facebook.com/hashtag/learntoday?__eep__=6\u0026amp;__cft__%5B0%5D=AZXMPFTOCKhKuTu56KT9b5dqNnfusOCCFw3VQy4kWrq3ObA78SO_saXfwUH9tZaw0i77zKl3xq6TATy-TqkZJy9XxfExF40F3wljo_bMj6sJ90t_2ZCcSDVl8jLDDBTemvk\u0026amp;__tn__=*NK-R\"\u003e#learntoday\u003c/a\u003e เป็นไอเดียที่เอาจริงๆ ผมไม่ได้คิดขึ้นมาเองแต่แรกอันนี้ disclaimer ก่อนเลย มันเกิดจากตอนที่นั่งคุยกับโครี่อยู่แล้วอารมณ์ประมาณว่ามันน่าจะดีนะ ถ้าเรารู้สึกว่าเราได้เรียนรู้อะไรในทุกๆ วันชีวิตจะไม่น่าเบื่อเลย แล้วกว่าจะถึงวันศุกร์หรือการจะจัด sharing session กันความตื่นเต้นเวลาเราได้เรียนรู้อะไรใหม่ๆ มันจะหายไปหมดแล้ว เลยคิดว่าต้องหาอะไรที่มัน light weight กว่านั้นมาเป็นช่องทางในการแบ่งปัน เพื่อที่จะให้ทุกคนรู้สึกว่า มันไม่ใช่เรื่องยากเลยที่เราจะ share knowledge ซึ่งกันและกัน\u003c/p\u003e\n\u003cp\u003eแล้วผมจำได้ว่าย้อนไปไม่กี่เดือนก่อนหน้านี้ผมเคยอ่านบล็อกของ Basecamp ชื่อ \u0026ldquo;What did you learn at work today?\u0026rdquo; (\u003ca href=\"https://m.signalvnoise.com/what-did-you-learn-at-work-today/?fbclid=IwAR1X5QDddtLnYfsgpe6QNUyMj2AEzdmq2X84JKv4SEoM-5VS_EbkrKAM1Zs\"\u003ehttps://m.signalvnoise.com/what-did-you-learn-at-work-today/\u003c/a\u003e) ซึ่งเล่าให้ฟังว่า DHH เค้าใช้ฟีเจอร์ Automatic check-ins ที่ basecamp ยังไงบ้าง แล้วผมรู้สึกว่าเห้ยนี่มันเป็นไอเดียที่ดีมากเพราะช่องทางการสื่อสารเราเป็นแบบ async ไปเลย แม้แต่ knowledge sharing ก็ตาม\u003c/p\u003e","title":"#learntoday"},{"content":"ใช่ครับ ผมเพิ่งลาออกจากทีม แต่สำหรับผมที่ทำงานมาหลายที่ นี่น่าจะเป็นการลาออกที่สำหรับผมมัน Properly หรือภาษาผมเรียกว่า บ้านไม่บึ้ม ที่สุดละ เลยอยากจะบันทึกเก็บไว้หน่อย เพราะตอนจุดที่ผมตัดสินใจออกน้องในทีมก็ถามเหมือนกันว่ามันต้องยังไงบ้าง แต่เอาจริงๆ เรื่องแบบนี้ก็ไม่เคยมีใครสอนแหะ ผมจะข้ามสเต๊ปการตัดสินใจหรือเหตุผลว่าจะลาออกไปเลยนะครับ เพราะแต่ละคนน่าจะไม่เหมือนกัน ณ จุดนี้คือ ออกแน่ๆ ละ มาดูกันว่าต้องผ่านอะไรบ้าง\n⏰ The clock start ticking หลังจากที่เราตัดสินใจลาออกแล้ว ผมว่าช่วงที่ยากที่สุดคือวินาทีที่เราเริ่มนับนี่แหละครับ ซึ่งขึ้นอยู่กับเราว่าอยากใช้เวลานับถอยหลังแค่ไหนก่อนเราจะไป บางคน 2 สัปดาห์ บางคน 1 เดือน บางคน 3 เดือน สำหรับผมคิดว่า 1 เดือนนี่กำลังดีเพราะมากพอที่เราจะมีเวลา Wrap up หลายๆ อย่าง แต่ก็ไม่นานเกินไปจนเรารู้สึกเบื่อไปก่อน แล้วถ้าถามว่านับตั้งแต่เมื่อไร เอาจริงๆ คือนับตั้งแต่วันที่เราบอกคนที่รับผิดชอบเราและเพื่อนร่วมทีมเราว่าจะออกครับ นับตั้งแต่วินาทีนั้นแหละครับ ซึ่งจะพาเรามาสู่หัวข้อที่สอง\n💌 How to give a resign message ในบรรดาขั้นตอนทั้งหมดตลอด 1 เดือน นี่คือจุดที่อึดอัดที่สุดและโล่งใจที่สุดครับ ไม่ว่าเราจะออกด้วยเหตุผลอะไรก็ตาม จุดนี้คือจุดที่เราตัดสินใจร่ำลากัน ซึ่งคำแนะนำกว้างๆ ของผมคือ ให้เลือกใช้คำที่มันชัดเจนที่สุด ไม่ต้องอ้อมหรือชักแม่น้ำทั้งห้าครับ นี่คือจุดที่เราตัดสินใจ วินาทีที่เราพูดหรือพิมพ์แล้วกด Enter ไปแล้วนั่นแหละ เราเลือกที่จะตัดสินใจแล้วครับ\nอีกคำแนะนำคือให้เวลาคนที่เราจะคุยด้วยซึมซับ Message ด้วยครับ ไม่ใช่จะออกเดี๋ยวนี้ ต้องคุยเดี๋ยวนี้เลย จะบินแล้วโว้ย ไม่ได้ครับๆ ถ้าให้อีกฝ่ายเลือกเวลาจะช่วยให้เค้ามีเวลาคิดอะไรมากขึ้น แต่อย่างที่บอกครับ เวลาเริ่มนับตั้งแต่วินาทีที่เรากด Enter ไปแล้วนั่นแหละ\nซึ่งแน่นอนว่าจะมีการถามเหตุผลตามมาหรือขอฟีดแบคตามมาแทบจะ 100% ณ จุดนี้ ผมเชื่อว่าแต่ละคนมีวิถีทางของตัวเองครับ ว่าอยากจะบอกเหตุผลหรือไม่บอก อยากจะซัดหน้าแม่งหรืออยากจะคุยกันดีๆ สำหรับผมคือบอกไปหมดเลยครับ คุยกันดีๆ เพราะอย่างน้อย เราได้พูดอย่างที่เราอยากพูดไปหมดแล้ว แล้วเราจะไม่มีสิ่งที่คาใจอยู่อีกเลย\nอ่อและสิ่งหนึ่งที่ไม่ควรลืมเลยในการสนทนาคือ วันสุดท้ายที่เราจะทำงานกับทีมครับ เพราะเค้าจะได้เริ่มคิดถึงการหาคนมาทดแทนเราได้ หรือเริ่ม process ในการลบ Credentials ต่างๆ ออกจากระบบว่าต้องเสร็จเมื่อไรครับ\nอีกอย่างนึงคือ การคุยกันอาจจะมีมากกว่าหนึ่งรอบครับ ก็ใจแข็งๆ ไว้นะครับ ช่วงนี้อึดอัดที่สุดละ แต่ถ้าผ่านไปได้ ที่เหลือไม่มีอะไรยากแล้วครับ\n🌥 Lower your light พอผ่านขั้นตอนแรกมาแล้ว ขั้นตอนต่อมาจะใช้เวลายาวนานหน่อยหรือก็คือตลอดช่วงเวลาที่เรานับถอยหลังอยู่ คือเราต้องค่อยๆ ลดบทบาทตัวเองในทีมลงครับ ซึ่งของพวกนี้ต้องค่อยๆ ให้ทีมซึมซับไป ในขณะเดียวกันเราเองก็ต้องปรับพฤติกรรมด้วย ยกตัวอย่างเช่น\nเวลา Meeting ถ้าเราเป็นคนที่ออกความเห็นบ่อย หรือมีคน Engage มาหาเราบ่อย สิ่งที่เราต้องเริ่มทำเวลานี้คือ หาตัวตายตัวแทนครับ แรกๆ Message มันจะเข้ามาหาเราอยู่ดี เราต้องคอยเตือนตัวเองอยู่ตลอดว่า เราต้องให้คนที่อยู่ข้างๆ เรา Step up ขึ้นมารับแล้วนะ ในกรณีที่เค้าไม่เคยรับ เวลามีน้องมาถามว่าทำนู้น ทำนี่ดีมั้ย ทำไงต่อดีพี่ สิ่งที่เราทำได้คือบอกน้องไปตามตรงว่า “พี่ไม่อยู่แล้วนะ ตัดสินใจเองเลย” แรกๆ น้องอาจจะไม่ชิน เพราะของมันเคยทำมาหลายเดือน จังหวะนี้อาจจะมีหลุดมาถามบ้าง ก็อาจจะช่วยตัดสินใจบ้าง ขึ้นอยู่กับเรา แต่พยายามอย่ามากเกินไปครับ ถ้าเราเป็นคนนึงที่รู้สึกว่ามีความรับผิดชอบเต็มมือ แล้วพอเริ่มปล่อยมือแล้วมันเหงาๆ เบื่อๆ ก็ทำใจร่มๆ ไว้นะครับ ถ้าเรายังต้องทำแบบเดิมอยู่นั่นคือการทำร้ายทีมแบบตั้งใจเลยครับ ผมบอกได้แค่ว่า just let it go ซึ่งถ้ารู้สึกแบบนั้นจริงๆ คำแนะนำผมคือ เริ่มศึกษางานใหม่ไว้ก่อนเลยก็ดีนะครับ ว่าควรจะต้องรู้อะไรบ้าง ถ้าสมมติงานที่เราทำมันต่างไปจากเดิมทั้ง Business และ Tech จะช่วยลดความเบื่อลงไปได้บ้างครับ แต่สิ่งสำคัญคือ เรายังทำงานกับทีมปัจจุบันอยู่ เพราะฉะนั้นเคารพเวลาที่เราทำงานกับทีมตามที่ตกลงกันไว้ด้วยก็พอครับ\nพอเราทำแบบนี้ไปเรื่อยๆ ทีมจะเริ่มเรียนรู้แล้ว การตัดสินใจต่างๆ หรือความรับผิดชอบต่างๆ มันจะค่อยๆ ลดลงไปจากเราเองครับ แต่แน่นอนว่านั่นก็ไม่ใช่ทั้งหมดของสิ่งที่เราทำใช่มั้ยครับ มันจะต้องมีบางอย่างเสมอที่เรารู้และเป็นมุมมองของเรา ซึ่งจะพาเรามาสู่หัวข้อถัดไป\n📚 Setting up your replacement to win ผมได้ไอเดียนี้มาตอนอ่าน Designing Your Work Life ตอนช่วงหนึ่งเดือนสุดท้ายนี่แหละครับ ซึ่งไอเดียของมันคือ ถ้าเรามีโอกาสได้คุยกับคนที่จะเข้ามาแทนที่เรา เราอยากจะบอกอะไรเค้า อาจจะดูเหมือนยาก แต่จริงๆ แล้วสำหรับผมสนุกมากครับ เพราะตอนเราเขียนมันจะมีความรู้สึกแบบปรารถนาดี อยู่ในข้อความเราโดยอัตโนมัติ แล้วความรู้สึกของการได้ช่วยใครซักคนที่จะมารับช่วงต่อจากเรานี่ ผมบอกได้เลยว่ามันเติมเต็มจิตใจมากครับ ถึงเราจะไม่เคยเจอหน้า หรือไม่มีโอกาสที่จะได้เจอเค้าก็ตาม\nซึ่งเอาจริงๆ เหมือนขั้นตอนนี้น่าจะใช้เวลานาน แต่ผมใช้เวลา 1 วันเต็มๆ เขียนก็เสร็จแล้วครับ หัวข้อที่เขียนอันนี้แล้วแต่เราเลยว่าเราอยากให้เค้ารู้อะไรบ้างตัวอย่างที่ผมเขียนจะมี\nทีมนี้เกิดขึ้นมาได้ยังไง อะไรคือความรับผิดชอบเรา สิ่งที่เราต้องทำในแต่ละวัน ช่องทางการติดต่อสื่อสารต่างๆ ที่เกี่ยวกับทีม Key Person ในทีมหรือที่เราต้องติดต่อด้วยมีใครบ้าง แหล่งข้อมูลต่างๆ ที่เกี่ยวกับงานที่เราทำจะไปหาได้ที่ไหน สิ่งที่เราต้องรู้ ถ้าจะทำงานให้ได้ดีเช่น เทคโนโลยีที่เราใช้หรือ Architecture ของงาน คำแนะนำอีกอย่างผมคือ พยายามเขียนในแบบที่เราอยากอ่านครับ แล้วเราจะเขียนมันออกมาได้ดีเอง พอเขียนเสร็จแล้วเราก็ฝากไว้กับคนที่เราคุยด้วยตอนแรกนั่นแหละครับ เพื่อให้เค้าส่งต่อให้คนที่มาแทนเราต่อไป\n🌻 The Final Gratitude ผมเชื่อว่าหลายคนจะทำสิ่งนี้ในวันสุดท้าย ซึ่งผมก็ทำวันสุดท้ายเหมือนกัน เรียกได้ว่าไม่กี่ชั่วโมงสุดท้ายด้วย ผมบอกได้เลยว่ามันคือความทรงจำดีๆ สุดท้ายที่เราจะสามารถมอบให้กับทีมได้ครับ เพราะหลังจากนี้ปัญหาหรืออะไรต่างๆ ที่เป็นความทรงจำไม่ดี มันไม่ได้ตามเราไปด้วย เพราะฉะนั้นใช้เวลาให้คุ้มค่าครับ\nคำแนะนำผมคือ อย่าไปคิดสดเอาหน้างานครับเพราะยิ่งเราทำงานกับทีมมานาน ความทรงจำเราจะเยอะมาก ถ้าเป็นไปได้ก็นึกๆ ไว้บ้างอาจจะไม่ถึงขนาด นึกมาตลอดทั้งเดือน แต่ให้มั่นใจว่าสิ่งที่เราพูดออกไป เราจะไม่รู้สึกเสียดายว่า ทำไมกรูไม่พูดเรื่องนี้ไปว้าาา แค่นั้นแหละครับ แล้วมันจะเป็นช่วงเวลาที่ดีและเราจดจำไปอีกนานเลย\nและสิ่งที่อยากจะย้ำอีกอย่างคือ หลายครั้งจุดนี้มันเป็นแค่การจากลากันชั่วคราวครับ หลังจากนี้อีก 2 ปี 5 ปี 10 ปี สุดท้ายเราอาจจะวนเวียนกลับมาได้ทำงานกับหนึ่งในคนที่เรากล่าวลากันในวันนี้ก็รักษาน้ำใจกันไว้ดีๆ นะครับ\nหมดแล้วครับ กว่าจะมาถึงวันสุดท้าย ผมหวังว่าคำแนะนำผมจะมีประโยชน์กับคนอื่นบ้างนะครับ 👋\n","permalink":"https://yothinix-com.pages.dev/how-to-resign/","summary":"\u003cp\u003eใช่ครับ ผมเพิ่งลาออกจากทีม แต่สำหรับผมที่ทำงานมาหลายที่ นี่น่าจะเป็นการลาออกที่สำหรับผมมัน Properly หรือภาษาผมเรียกว่า บ้านไม่บึ้ม ที่สุดละ เลยอยากจะบันทึกเก็บไว้หน่อย เพราะตอนจุดที่ผมตัดสินใจออกน้องในทีมก็ถามเหมือนกันว่ามันต้องยังไงบ้าง แต่เอาจริงๆ เรื่องแบบนี้ก็ไม่เคยมีใครสอนแหะ ผมจะข้ามสเต๊ปการตัดสินใจหรือเหตุผลว่าจะลาออกไปเลยนะครับ เพราะแต่ละคนน่าจะไม่เหมือนกัน ณ จุดนี้คือ ออกแน่ๆ ละ มาดูกันว่าต้องผ่านอะไรบ้าง\u003c/p\u003e\n\u003ch2 id=\"-the-clock-start-ticking\"\u003e⏰ The clock start ticking\u003c/h2\u003e\n\u003cp\u003eหลังจากที่เราตัดสินใจลาออกแล้ว ผมว่าช่วงที่ยากที่สุดคือวินาทีที่เราเริ่มนับนี่แหละครับ ซึ่งขึ้นอยู่กับเราว่าอยากใช้เวลานับถอยหลังแค่ไหนก่อนเราจะไป บางคน 2 สัปดาห์ บางคน 1 เดือน บางคน 3 เดือน สำหรับผมคิดว่า 1 เดือนนี่กำลังดีเพราะมากพอที่เราจะมีเวลา Wrap up หลายๆ อย่าง แต่ก็ไม่นานเกินไปจนเรารู้สึกเบื่อไปก่อน แล้วถ้าถามว่านับตั้งแต่เมื่อไร เอาจริงๆ คือนับตั้งแต่วันที่เราบอกคนที่รับผิดชอบเราและเพื่อนร่วมทีมเราว่าจะออกครับ นับตั้งแต่วินาทีนั้นแหละครับ ซึ่งจะพาเรามาสู่หัวข้อที่สอง\u003c/p\u003e\n\u003ch2 id=\"-how-to-give-a-resign-message\"\u003e💌 How to give a resign message\u003c/h2\u003e\n\u003cp\u003eในบรรดาขั้นตอนทั้งหมดตลอด 1 เดือน นี่คือจุดที่อึดอัดที่สุดและโล่งใจที่สุดครับ ไม่ว่าเราจะออกด้วยเหตุผลอะไรก็ตาม จุดนี้คือจุดที่เราตัดสินใจร่ำลากัน ซึ่งคำแนะนำกว้างๆ ของผมคือ ให้เลือกใช้คำที่มันชัดเจนที่สุด ไม่ต้องอ้อมหรือชักแม่น้ำทั้งห้าครับ นี่คือจุดที่เราตัดสินใจ วินาทีที่เราพูดหรือพิมพ์แล้วกด Enter ไปแล้วนั่นแหละ เราเลือกที่จะตัดสินใจแล้วครับ\u003c/p\u003e","title":"How to ลาออก ยังไงไม่ให้บ้านบึ้ม"},{"content":"ก่อนที่จะเขียนบล็อกนี้นี่คิดอยู่นานว่าจะเล่าเรื่องเกี่ยวกับ 3 ปีที่ผ่านมายังไง คือมันมีเหตุการณ์ที่เกิดขึ้นหลากหลายมากจนไม่รู้จะเล่าเรื่องไหนก่อน โชคดีที่เมื่อวานไม่รู้คุยกันแบบไหน เรื่องนี้มันก็ถูกยกขึ้นมาแล้วพอมองย้อนกลับไป นี่แหละเรื่องนี้แหละคือ Once in a life time story เลย แล้วผมจะมาเล่าให้ฟังในบล็อกนี้อีกรอบครับ\nTraditional Leader ก่อนที่จะพูดถึงคำว่า Emergent Leadership ต้องย้อนกลับไปถึง Traditional Leader ก่อน ก่อนหน้านี้มาตลอดชีวิต (ใช่! ต้องใช้คำว่าตลอดชีวิต) ผมมีความเชื่อว่าถ้าเราจะเปลี่ยนแปลงอะไรบางอย่างให้ได้ เราต้องมี Power และการจะมี Power ได้เราต้องมี Role ต้องมีตำแหน่ง หรืออะไรก็แล้วแต่นะ ในการที่จะมอบ Power ให้เราสามารถเปลี่ยนแปลงบางอย่างได้\nพอเราเชื่อแบบนี้แล้วเนี่ย วิธีการแก้ปัญหาของผมมันเลยเป็นเหมือนเดิมมาตลอดคือ ไม่ว่าเราจะเริ่มต้นใหม่ที่ไหน กับทีมใหม่ที่ไหน สิ่งที่เกิดขึ้นคือ เราจะหาช่องที่จะทำให้เราไปอยู่ในจุดที่สูงที่สุดให้ได้ เพื่อที่เราจะได้มองลงมาแล้วเราจะสามารถบอกได้ว่า นี่ไปทางซ้ายสิ ไปทางขวาสิ โดยไม่ต้องกังวลกับผลลัพธ์ของการตัดสินใจมากนัก (เพราะมันขึ้นมาสูงแล้วไง)\nนอกจากนี้ผมบอกเลยว่า พอเรามี Role มีตำแหน่ง อยู่ข้างหลัง ไม่ว่าจะเป็น Senior, Lead, Manager หรืออะไรก็ตามติดหลังอยู่ เราจะมีความมั่นใจมาก (แต่ตอนนั้นยังไม่รู้สึกนะ) เวลาเราออกไปเจอคนอื่น ซึ่งอันนี้พอผมมามองย้อนกลับไปมันไม่ใช่เรื่องแปลกเลย เพราะโครงสร้างอำนาจทางสังคมที่ผมโตมาตลอดชีวิต มันนำให้เราต้องทำแบบนี้\nMy Story ยังครับ ยังไม่ถึง Emergent Leadership เพราะพูดเลยอาจจะไม่เห็นภาพ ผมเลยจะมาโม้เรื่องราว Once in a life time ของผมและสิ่งที่ผมเพิ่งมาเรียนรู้ใน 3 ปีที่ผ่านมาให้ฟัง แต่ถ้าอดทนอ่านไม่ไหวอยากรู้ว่า Emergent Leadership คืออะไร ข้ามไปหัวข้อถัดไปได้เลยครับ\nย้อนกลับไปทีมแรกในเรื่องราวนี้ เรามีภารกิจต้องส่งมอบซอฟท์แวร์ตัวนึงซึ่ง ทั้งทีมไม่มีประสบการณ์ทำทั้งหมดเลย และยิ่งกว่านั้นคือไม่รู้จะเริ่มต้นยังไง สิ่งที่ผมตัดสินใจทำในเวลานั้นคือ \u0026ldquo;เราต้องเป็นคนนำทุกอย่างเอง เพราะเราเชื่อว่าเราเก่งที่สุด\u0026rdquo; (ขึดเส้นใต้คำนี้เลย) ซึ่งโอเคมันทำให้งานมันเดินหน้าไปได้ แต่ผมเหนื่อยมาก เพราะพอเราเชื่อแบบนี้ เราเลยคาดหวังสูงมากในสิ่งที่เรานำคนในทีมไป แล้วพอทีมทำไม่ได้ในสิ่งที่เราหวัง การผิดหวังสะสมมากขึ้นเรื่อยๆ มาวันนึงมันก็ระเบิดออกในวันสุดท้าย ซึ่งมันควรจะเป็นวันที่เราฉลองความสำเร็จ แต่กลับผิดหวังแทนและเราจมอยู่กับความผิดหวังนั้นนานใช้ได้เลย\nทีมที่สอง ต้องบอกว่าผมก็ลืมเรื่องก่อนหน้านี้ไปเลย เพราะเราได้เริ่มต้นใหม่และเราเด็กที่สุด เราก็ทำงานไปเรื่อยๆ ไม่ได้คิดอะไร แต่พอถึงจุดนึงช่วงใกล้ๆ จะทำงานครบปีแรก มันมีเหตุการณ์หลายเหตุการณ์มากที่ทำให้มันวนกลับมาตั้งคำถามว่า \u0026ldquo;เราจะอยู่รอดได้ยังไง\u0026quot;​ ซึ่งพอระบบมันตั้งคำถามแบบนี้ คำตอบอัตโนมัติ มันเลยเป็นคำตอบเดิมว่า \u0026ldquo;เราต้องเป็นคนนำทุกอย่างเอง เพราะเราเชื่อว่าเราเก่งที่สุด\u0026rdquo; พอคำตอบเป็นแบบนี้ตอน Review Performance สิ่งที่ผมทำคือ ผมบอกหัวหน้าผมว่า ผมอยากเป็นลีดนะ แล้วก็บอกเหตุผลกับเรื่องราว 1 2 3 4 หัวหน้าก็คุยกันอยู่แปปนึงสองคน แต่สุดท้ายผมก็ได้ Role นั้นมาและเป็นสิ่งที่ผมเข้าใจว่าผมได้ Power สำหรับการเปลี่ยนแปลงแล้ว\nแต่ครั้งนี้ต่างออกไปจากทีมแรกที่พูดถึงข้างบน ความสัมพันธ์ของผมกับคนในทีมมันไม่ได้สร้างมาแบบนั้นแต่แรก เราเป็นเพื่อนกันมาตลอด แล้วอยู่มาวันนึงเราต้อง step up ขึ้นมา ตอนนั้นผมจำได้เลยว่าผมทำตัวไม่ถูก เพราะไม่รู้ว่าต้องทำไง แต่ตอนนั้นดันมีความเชื่อผิดๆ ประมาณว่าเราต้องไม่เหมือนเดิม พอผ่านมาผมเลยเริ่มที่จะวางตัวอีกแบบกับเพื่อนร่วมทีม แล้วลึกๆ ผมอึดอัดมากเพราะเชื่อว่าเราเป็นเพื่อนกันเหมือนเดิมไม่ได้แล้ว ถ้ามามองย้อนกลับไปตอนนี้ผมเดาว่าทำแบบนั้นไปเพื่อที่จะให้คนรอบตัวรู้ว่าผมมี Power นะ อะไรแบบนี้ ซึ่งเป็นเรื่องที่ผิดมาก เพราะมันไม่จำเป็นต้องทำอย่างนั้นเลย กว่าผมจะรู้ตัวเรื่องนี้ก็ผ่านมาซักพักนึงแล้วพี่ในทีมก็ให้ Feedback มาว่า ผมเปลี่ยนไปนะ ทำแบบนี้มันไม่โอเคนะ นั่นแหละผมเลยเข้าใจเรื่องนี้แล้วกลับมาเป็นเหมือนเดิม\nทีมที่สาม นี่แหละที่เรื่องราวมันจะต่างออกไปจากที่ผ่านมา ด้วยระบบความคิดที่ยังเชื่อว่า เราต้องมี Power และ Role นะถึงจะเปลี่ยนแปลงอะไรได้ และเราต้องไปอยู่ในจุดสูงสุดเราถึงจะบอกได้ว่าไปซ้ายสิ ไปขวาสิ ทุกการกระทำมันเลยออกมาคล้ายๆ หนังม้วนเดิมจากสองทีมที่ผ่านมา แต่สิ่งที่ต่างออกไปคือ ทีมไม่ได้เออ ออ ห่อหมกไปกับผมทุกเรื่องอีกแล้ว ผมโชคดีมากที่ทีมที่นี่คุยกันด้วยเหตุผลเยอะมาก แต่ตอนนั้นผมยังไม่เข้าใจหรอก สิ่งที่ผมเข้าใจตอนนั้นคือ สิ่งที่เราต้องการมันไม่ได้รับการตอบสนอง แล้วสิ่งที่แย่กว่าเข้าใจแบบนั้นคือการตัดสินใจว่า \u0026ldquo;อยากทำอะไรทำเลย เราจะไม่ออกความเห็นแล้ว\u0026rdquo; ซึ่งในความคิดเนี่ย มันคือความต้องการการรับฟัง แต่ผมเข้าใจว่าทีมไม่ได้รับฟังผมอีกแล้ว ซึ่งเป็นความคิดที่เข้าใจผิดไปไกลมาก\nสิ่งที่แย่กว่าการเข้าใจแบบนั้น การตัดสินใจแบบนั้นคือสิ่งที่ผมทำหลังจากนั้นอีกครับ ถึงแม้ผมจะพยายามปกป้องตัวเองด้วยการไม่ออกความเห็นกับเรื่องต่างๆ แต่สิ่งหนึ่งที่มันโกหกไม่ได้คือสีหน้าของผมเอง ซึ่งมันออกมาเองโดยที่เราไม่สามารถควบคุมได้ และนั่นเป็นสิ่งที่ทำให้ทีมรู้สึกแย่กับผมมากจนกว่าผมจะมารู้ตัวก็คือ Review performance แล้วที่มีเพื่อนร่วมทีมเขียนออกมา ณ​ จุดนั้นผมบอกเลยว่าผมรู้สึกว่าผมไม่เหมาะกับที่นี่ละ มันต้องออกละเพราะธรรมชาติเราไม่ได้ถูกสร้างมาให้เก็บอะไรไว้แบบนี้ และผมรู้เลยว่าถ้าเก็บไว้ต่อไปมันระเบิดแน่ๆ เหมือนในเรื่องแรกข้างบน และผมอยู่ในสภาวะแบบนั้นนานมาก มากจนในบางครั้งผมก็ถามตัวเองว่า ผมมาทำอะไรที่นี่\nทีมที่สี่ ก่อนจะมาถึงทีมที่สี่ต้องบอกเลยว่าสภาวะที่อยู่ก่อนหน้านั้นมันทำลายความมั่นใจทุกอย่างที่ผมเคยเชื่อไปเยอะมากและ Review performance จังหวะก่อนที่จะมาอยู่กับทีมที่สี่นี่คือจุดเปลี่ยนเลย ถ้ามามองย้อนกลับไปผมว่าครั้งนี้แหละที่ผมเปิดรับทุก Feedback แล้วจะเอาไปแก้ให้หมด เพราะมันไม่มีอะไรจะเสียแล้ว แล้วต้องการหาทุกทางที่จะออกจากสภาวะก่อนหน้านี้ไปให้ได้\nภาพข้างบนเป็นหนึ่ง lane ในบอร์ด Trello ส่วนตัวของผมซึ่งผมกลับมาดูมันบ่อยมากในปีนั้น มันตอบคำถามหลายๆ อย่างจากหลายๆ เรื่องที่ผ่านมาตั้งแต่ผมเล่ามาข้างบนได้ว่า ผมควรจะคิดยังไง ผมบอกเลยว่า ตอนนี้ถ้าอ่านเราจะรู้สึกว่ามันไม่ใช่อะไรที่มันซับซ้อนเลยใช่มั้ยครับ แต่ในเรื่องราวที่ผ่านมาก็น่าจะเห็นแล้วว่าเรื่องแบบนี้ ถ้ามันไม่มีใครมาบอก มา Feedback ผมบอกเลยว่า ยังไง ก็มองไม่เห็นครับ ก็เห็นแล้วนี่ว่าผมมองไม่เห็นมานานแค่ไหน\nผมวาง Role และความอยากได้ Power อะไรทิ้งออกไปเยอะมาก แล้วเลือกที่จะเริ่มต้นใหม่หมด แต่ไม่ใช่วิธีเดิมอีกต่อไปแล้ว ผมไม่ได้เชื่อแล้วว่า เราทำ เราเก่ง เราจะได้ Power แต่กับทีมนี้ หลังจากที่อยู่มาความคิดมันเปลี่ยนไปเป็น เราเชื่อว่าเพื่อนร่วมทีมเราจะทำได้และเราจะช่วยเค้าเต็มที่เพื่อให้เค้าทำได้ (โดยที่เราไม่เป็น Hero) อาจจะฟังดู Abstract แต่ผมมีตัวอย่างง่ายๆ ครับ สมมติคนในทีมติดอะไรแล้วขอความช่วยเหลือ ก่อนหน้านี้ผมสารภาพเลยว่าเวลาเห็นคนพิมพ์ช้า พิมพ์ผิด พิมพ์ถูก ผมจะรำคาญมากแล้วจะ end up ด้วยการแย่งคีย์บอร์ดคนๆ นั้นมาพิมพ์เอง เพื่อให้มันผ่านไปได้ แต่พอเราเชื่อว่า เพื่อนร่วมทีมเราจะทำได้ มันยากมากที่ผมจะหยิบคีย์บอร์ดมาพิมพ์เองเลย แต่จะเอาใจช่วยให้เพื่อนร่วมทีมของผม ทำเรื่องนั้นสำเร็จได้ด้วยตัวเอง แล้วผมบอกเลยว่าเรื่องนี้เกิดขึ้นบ่อยจนผมเห็นผลตามมาเลยครับ\nสิ่งที่ผมเรียนรู้อีกอย่างนึงในทีมนี้คือ การฟังครับ และผมบอกเลยว่าตอนอยู่กับทีมนี้ใหม่ๆ ผมยังไม่ได้เรียนรู้เรื่องนี้ คือพอเราเป็นคนที่อยู่ในกลุ่มคนที่มีอายุมากกว่าคนในทีมส่วนใหญ่ สมองเราจะตอบสนองกับคำถามต่างๆ ของคนอื่นไวมาก เพราะเราอาจจะเคยผ่านเรื่องประมาณนี้มาแล้ว แต่สิ่งหนึ่งที่คนในทีมนี้จะย้ำกันเสมอคือ ยิ่งถ้าเราเป็นพี่มากเท่าไร เรายิ่งต้องพูดให้ช้ากว่าคนอื่น ไม่งั้นคนอื่นก็จะไม่ได้เรียนรู้อะไรเลย และไม่ว่าไอเดียนั้นจะเหมือนกับความคิดเรามากแค่ไหน แต่มันมีความต่างกันมากระหว่างที่คนนั้นพูดไอเดียนั้นเอง หรือเราเป็นคนพูดไอเดียนั้นเอง ผมมีสถานการณ์สมมติสำหรับคนเป็นพี่ที่น่าจะเคยเจอคือ เวลาทีมต้องการไอเดียอะไรซักอย่างแล้วเราเป็นพี่สุด น้องโดยอัตโนมัติจะหันมาหาพี่ก่อนเสมอ ณ จุดนั้นเราจะทำยังไงครับ?\nถ้าเป็นเมื่อก่อนผมบอกเลยว่า พอเห็นคนหันมาอย่างนี้ผมจะรู้สึกเลยว่าเรามี Power ละและทีมคาดหวังเราอยู่ เราต้องไม่ทำให้เค้าผิดหวังซิ แต่นั่นคือ Hero ครับ ตอนผมรู้ตัวเรื่องนี้ผมก็เลยคิดค้นวิธีหลบเรื่องนี้ขึ้นมาคือ จังหวะที่ทีมหันมาหาผมทั้งทีม แทนที่ผมจะแก้ปัญหา ผมหันไปถามคนในทีมซักคนแทนด้วยคำถามง่ายๆ ว่า \u0026ldquo;เราคิดว่าไง\u0026rdquo; ง่ายๆ อย่างนั้นเลยครับ และเวิร์คทุกครั้ง ฮ่าๆ\nผมโชคดีมากตอนที่ผมมาอยู่ทีมที่สี่เราให้ Feedback กันบ่อยมากครับทั้ง 1:1 หรือ Retrospective เราจะรู้ตัวเองตลอดว่าสิ่งที่เราทำไปมันส่งผลกระทบแค่ไหน และเพราะการให้ Feedback ตลอดนี่แหละ เลยเป็นเครื่องยืนยันว่าผมเปลี่ยนความคิดไปแล้วจริงๆ มันมีเหตุการณ์นึงที่ยืนยันเรื่องนี้คือ มีครั้งนึงผม Vacation leave ไปหลายวันมาก แล้วหลังจากผมกลับมาแปปนึงก็ Retrospective พอดี แล้วน้องในทีมก็ให้ Feedback มาประมาณว่า \u0026ldquo;ขาดผมไปรู้สึกเหมือนขาดที่พึ่งทางใจ\u0026rdquo; จังหวะที่ผมเห็นโพสอิทใบนี้ ผมคิดในใจเลยว่า \u0026ldquo;ชิปหายแล้ว! เราเผลอเป็น Hero อีกแล้วเหรอวะ\u0026rdquo; ซึ่งผมมั่นใจเลยว่าถ้าเป็นผมก่อนหน้านี้ผมน่าจะยิ้มอยู่ในใจว่าเราได้ Power มาละ แต่จุดนี้ผมบอกได้เลยว่า ผมไม่ได้อยากได้ ผมอยากให้ทีมทำงานกันเองได้ แล้วผมจะได้ไปทำอย่างอื่นที่ผมอยากทำ\nEmergent Leadership พออ่านมาถึงจุดนี้ก็ยังอาจจะเกิดคำถามอยู่ว่าแล้วสรุป Emergent Leadership นี่มันคืออะไรกันแน่ ถ้าสรุปเอาแบบนิยามสั้นๆ ที่ผมเข้าใจคือ สภาวะผู้นำที่เกิดขึ้นเองโดยธรรมชาติครับของทีมซึ่งทุกคนในทีมสามารถเป็นผู้นำในเรื่องหนึ่งๆ ได้และเป็นผู้ตามในอีกเรื่องหนึ่งได้ในเวลาเดียวกัน ซึ่งต้องบอกว่า สาเหตุที่ผมไม่พูดนิยามมันตั้งแต่แรก แต่เลือกที่จะเล่าเรื่องมายาวมาก เพราะว่ามันยากที่จะเข้าใจมากครับว่าผู้นำที่เกิดขึ้นเองโดยธรรมชาติ มันเกิดขึ้นได้ยังไงและมันยังสามารถตีความไปได้อีกหลายแบบมากๆ\nหน้าที่ของ Emergent Leadership ในแบบที่ผมเข้าใจคือเราจะไม่ชี้ว่าไปซ้ายไปขวานะ แต่เราจะมีหน้าที่ทำให้ทีมเข้าใจว่าไปซ้ายแล้วจะเกิดอะไรขึ้นบ้าง ไปขวาแล้วจะเกิดอะไรขึ้นบ้าง แต่สุดท้ายแล้วการตัดสินใจอยู่ที่ทีมครับว่าจะไปทางไหน ซ้ายหรือขวา ซึ่งสุดท้ยแล้วมันอาจจะไม่ตรงกับที่เราคิดก็ได้ แต่สิ่งที่เราได้มาคือ ทีมได้ Ownership ของการตัดสินใจนั้นไปเลยโดยที่ไม่ต้องมาเกิดคำพูดทีหลังว่า นี่ถ้าตอนนั้นเราไปแบบนี้นะ\u0026hellip;​ เพราะทุกคนตอนนี้รับผิดชอบร่วมกันไปแล้ว แล้วทุกคนจะมีอิสระที่จะทำอะไรก็ได้ให้เกิดผลลัพธ์ดีที่สุดสำหรับตัวเองและทีม ด้วยเป้าหมายเดียวกันไปโดยอัตโนมัติเลยครับ\nTrust-Respect-Honest ต้องบอกว่าหลังจากเรื่องราวทั้งหมดผมเลยเข้าใจคำว่า Emergent Leadership ครับ แต่บอกได้เลยว่าคำๆ นี้ไม่ได้อยู่ในหัวเลย ต้องบอกว่าพอความเชื่อเรื่อง Traditional Leaders ผมโดนทำลายลง ในหัวผมเริ่มพัฒนาความเชื่อขึ้นมาใหม่ครับ จิงๆ ต้องบอกว่าสภาพแวดล้อมทำให้ผมเชื่อเรื่องนี้ด้วย แล้วผมสรุปออกมาเป็น 3 value ที่สนับสนุนซึ่งกันและกัน\nอย่างแรกเลยคือ Trust ครับ จากโมเม้นต์ที่ผมเชื่อว่าผมเก่งที่สุดไปจนถึงทีมติดปัญหาแล้วผมไม่จับคีย์บอร์ด อันนี้คือพัฒนาการเรื่อง Trust เลยครับ คือผมคิดว่าเราควร \u0026ldquo;เชื่อใจ\u0026quot;​ เพื่อนร่วมทีมให้มาก เชื่อว่าเค้าจะทำงานได้สุดความสามารถที่เค้ามีเพื่อที่จะแก้ปัญหาต่างๆ ไปได้\nอย่างที่สองคือ Respect ครับ อันนี้ผมเชื่อว่า ไม่ว่าเค้าจะเพิ่งมาทำงานใหม่ๆ หรือเป็นเพื่อนร่วมทีมที่ประสบการณ์โชคโชน การที่เรา \u0026ldquo;ความเคารพ\u0026quot;​ ในความคิดเห็นของทุกคนสำคัญมากครับ เพราะเราจะได้เรียนรู้สิ่งใหม่ๆ อยู่เสมอและเราอาจจะเจอทางที่เราคาดไม่ถึงก็ได้\nอย่างที่สามคือ Honest ครับ ต้องบอกว่าตอนแรกผมคิดได้แค่ 2 ข้อบนมานานมากแต่ก็รู้สึกว่าอะไรบางอย่างมันขาดไปจนมาเจอข้อนี้ครับ การที่เรา \u0026ldquo;ซื่อสัตย์\u0026rdquo; กับตัวเองว่าเราจะทำงานเต็มความสามารถที่เราทำได้ เราจะแสดงความคิดเห็นในสิ่งที่เราคิดจริงๆ เป็นสิ่งสำคัญมาก เพราะมันช่วยให้ทีมสามารถไปต่อได้ในกรณีที่เกิดความขัดแย้งครับและทำให้เราไม่ต้องมาเสียใจกับการตัดสินใจต่างๆ ทีหลังครับ\nและผมขอเสริมทั้งสามข้ออีกว่า ทุกข้อที่ผมพูดมานี่ Go both way ครับคือของแบบนี้เราทำคนเดียวไม่ได้ แต่ต้องเกิดขึ้นกับทุกคนในทีม แต่ผมก็เชื่อว่าเราไม่ต้องรอให้คนอื่นเริ่มก่อนก็ได้ครับถ้าอยากได้สิ่งนี้ เราเริ่มจากตัวเองก่อนได้เลย และถ้าสุดท้ายแล้วมันไม่ go both way เราก็ยังสามารถไว้อาลัยกับความต้องการเหล่านี้ของเราได้อยู่ครับ\nสุดท้ายแล้วต้องขอบคุณพี่เก๋ พี่กานต์ และทุกๆ คนที่ผ่านเข้ามาในชีวิตในเรื่องราวที่ผ่านมาที่สอนให้ผมรู้จักคำนี้ และทำให้ผมแขยงคำอย่างเช่น Senior, Lead, Manager ฯลฯ ไปอีกนานเลย\nOriginal Post at: https://yothinix.blogspot.com/2020/03/emergent-leadership-most-important.html\n","permalink":"https://yothinix-com.pages.dev/emergent-leadership/","summary":"\u003cp\u003eก่อนที่จะเขียนบล็อกนี้นี่คิดอยู่นานว่าจะเล่าเรื่องเกี่ยวกับ 3 ปีที่ผ่านมายังไง คือมันมีเหตุการณ์ที่เกิดขึ้นหลากหลายมากจนไม่รู้จะเล่าเรื่องไหนก่อน โชคดีที่เมื่อวานไม่รู้คุยกันแบบไหน เรื่องนี้มันก็ถูกยกขึ้นมาแล้วพอมองย้อนกลับไป นี่แหละเรื่องนี้แหละคือ Once in a life time story เลย แล้วผมจะมาเล่าให้ฟังในบล็อกนี้อีกรอบครับ\u003c/p\u003e\n\u003ch2 id=\"traditional-leader\"\u003eTraditional Leader\u003c/h2\u003e\n\u003cp\u003eก่อนที่จะพูดถึงคำว่า Emergent Leadership ต้องย้อนกลับไปถึง Traditional Leader ก่อน ก่อนหน้านี้มาตลอดชีวิต (ใช่! ต้องใช้คำว่าตลอดชีวิต) ผมมีความเชื่อว่าถ้าเราจะเปลี่ยนแปลงอะไรบางอย่างให้ได้ เราต้องมี Power และการจะมี Power ได้เราต้องมี Role ต้องมีตำแหน่ง หรืออะไรก็แล้วแต่นะ ในการที่จะมอบ Power ให้เราสามารถเปลี่ยนแปลงบางอย่างได้\u003c/p\u003e\n\u003ciframe src=\"https://giphy.com/embed/MCZ39lz83o5lC\" width=\"480\" height=\"257\" frameBorder=\"0\" class=\"giphy-embed\" allowFullScreen\u003e\u003c/iframe\u003e\n\u003cp\u003eพอเราเชื่อแบบนี้แล้วเนี่ย วิธีการแก้ปัญหาของผมมันเลยเป็นเหมือนเดิมมาตลอดคือ ไม่ว่าเราจะเริ่มต้นใหม่ที่ไหน กับทีมใหม่ที่ไหน สิ่งที่เกิดขึ้นคือ เราจะหาช่องที่จะทำให้เราไปอยู่ในจุดที่สูงที่สุดให้ได้ เพื่อที่เราจะได้มองลงมาแล้วเราจะสามารถบอกได้ว่า นี่ไปทางซ้ายสิ ไปทางขวาสิ โดยไม่ต้องกังวลกับผลลัพธ์ของการตัดสินใจมากนัก (เพราะมันขึ้นมาสูงแล้วไง)\u003c/p\u003e\n\u003cp\u003eนอกจากนี้ผมบอกเลยว่า พอเรามี Role มีตำแหน่ง อยู่ข้างหลัง ไม่ว่าจะเป็น Senior, Lead, Manager หรืออะไรก็ตามติดหลังอยู่ เราจะมีความมั่นใจมาก (แต่ตอนนั้นยังไม่รู้สึกนะ) เวลาเราออกไปเจอคนอื่น ซึ่งอันนี้พอผมมามองย้อนกลับไปมันไม่ใช่เรื่องแปลกเลย เพราะโครงสร้างอำนาจทางสังคมที่ผมโตมาตลอดชีวิต มันนำให้เราต้องทำแบบนี้\u003c/p\u003e\n\u003ch2 id=\"my-story\"\u003eMy Story\u003c/h2\u003e\n\u003cp\u003eยังครับ ยังไม่ถึง Emergent Leadership เพราะพูดเลยอาจจะไม่เห็นภาพ ผมเลยจะมาโม้เรื่องราว Once in a life time ของผมและสิ่งที่ผมเพิ่งมาเรียนรู้ใน 3 ปีที่ผ่านมาให้ฟัง แต่ถ้าอดทนอ่านไม่ไหวอยากรู้ว่า Emergent Leadership คืออะไร ข้ามไปหัวข้อถัดไปได้เลยครับ\u003c/p\u003e","title":"EMERGENT LEADERSHIP: สิ่งสำคัญที่สุดที่ได้เรียนรู้ตลอด 3 ปีที่ผ่านมา"},{"content":"My name is Yothin Muangsommuk. I\u0026rsquo;ve been in many roles in Software Development team such as Data Engineer, Software Engineer, Tech Lead, and Technical Consultant. My focus has always been improving a sustainability and maintainability through Technical Excellence and Software Craftsmanship. I also A Python enthusiasm, An occasional conference speaker, and a community organizer.\nInterests: Programming Language Design, Software Engineering, Distributed System\nTalks 2025 DE Connect: Bridge Data Minds - Demystifying Data Catalog (slide) 2024 LY Tech Week (Internal Conference) - Optimized Python Data Project Dependencies Management for Reliability and Storage Efficiency 2022 Grill the data - The rise of Dataset and its application (~1:11:50)(slide) 2022 Prodigy9\u0026rsquo;s ThursTech - Earthly: When Dockerfile and Makefile had a Baby (~14.30)(slide) 2022 Information Engineering, KMITL - Resiliency: How to survive in a fast pace Software Development World (Slide) 2021 PyCon APAC - Relearning Python the right way (slide) 2019 PySomTum #1 - Don\u0026rsquo;t reinvent the wheel with Django generic 2018 PyCon Thailand - Building a sustainable codebase with Type annotations 2017 Code Mania 101 - The Present, Past, and Future of Asynchronous Programming in Python 2016 Code Mania 100 - Token-based authentication ทำไปทำไม Classes 2024 - DataRockie\u0026rsquo;s Data Science Bootcamp #10 - Intro to Software Engineering 101 (Slide) 2022 - DataRockie\u0026rsquo;s Data Science Bootcamp #4 - Software Engineering Primer: Fighting complexity over time with peace (Slide) 2021 - DataRockie\u0026rsquo;s Data Science Bootcamp #3 - Along with the code - Tool, Tips and Techniques to make your Python programming life enjoyable (Slide) 2021 - DataRockie\u0026rsquo;s Data Science Bootcamp #2 - Beyond the basic: Modern Python in Action (Slide) Certificates 2024 - Dagster Labs - Dagster \u0026amp; dbt 2023 - Dagster Labs - Dagster Essentials 2021 - The LeSS Company B.V. - Certified LeSS Basics 2021 - Scrum Alliance - Certified ScrumMaster® (CSM®) 2021 - Coursera - Build a Modern Computer from First Principles: From Nand to Tetris (Project-Centered Course) 2019 - Coursera - Developing Applications with Google Cloud Platform Specialization Contact Facebook Page Twitter LinkedIn ","permalink":"https://yothinix-com.pages.dev/about/","summary":"\u003cp\u003eMy name is \u003cstrong\u003eYothin Muangsommuk\u003c/strong\u003e. I\u0026rsquo;ve been in many roles in Software Development team such as Data Engineer, Software Engineer, Tech Lead, and Technical Consultant. My focus has always been improving a sustainability and maintainability through Technical Excellence and Software Craftsmanship. I also A Python enthusiasm, An occasional conference speaker, and a community organizer.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eInterests\u003c/strong\u003e: Programming Language Design, Software Engineering, Distributed System\u003c/p\u003e\n\u003ch2 id=\"talks\"\u003e\u003cstrong\u003eTalks\u003c/strong\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e2025 DE Connect: Bridge Data Minds - \u003ca href=\"https://www.youtube.com/watch?v=M8Qd3WFNlDQ\"\u003eDemystifying Data Catalog\u003c/a\u003e (\u003ca href=\"https://docs.google.com/presentation/d/1NDV11kg8aBTc_ePQ2zKc3MEs-oOrHqVvuactmMDwAUs/edit?fbclid=IwY2xjawIyX_FleHRuA2FlbQIxMAABHfPIdyOEFEBPjq-nd5Hfjd9VEfLGtODPppquk6sJSLvgfeME6CnCg2GeJA_aem_L1pLVtBkeKSO82UTKB26fg#slide=id.g339ad692e10_0_0\"\u003eslide\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e2024 LY Tech Week (Internal Conference) - Optimized Python Data Project Dependencies Management for Reliability and Storage Efficiency\u003c/li\u003e\n\u003cli\u003e2022 Grill the data - \u003ca href=\"https://www.facebook.com/grillthedata/videos/5647912141943322\"\u003eThe rise of Dataset and its application\u003c/a\u003e (~1:11:50)(\u003ca href=\"https://docs.google.com/presentation/d/1QeL9lGeNiElcK4K6x78FG7GWxhsvLaXFKJJWta4QDP0/edit?usp=share_link\"\u003eslide\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e2022 Prodigy9\u0026rsquo;s ThursTech - \u003ca href=\"https://www.youtube.com/watch?v=-Sa7RH0146A\"\u003eEarthly: When Dockerfile and Makefile had a Baby\u003c/a\u003e (~14.30)(\u003ca href=\"https://docs.google.com/presentation/d/1NQ61LGGfP4rUBjTVKlmNlhYUcUlNsVjh436jpxiCpmg/edit?usp=share_link\"\u003eslide\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e2022 Information Engineering, KMITL - \u003ca href=\"https://www.facebook.com/yothinix/posts/10228062247799832\"\u003eResiliency: \u003cem\u003eHow to survive in a fast pace Software Development World\u003c/em\u003e\u003c/a\u003e \u003cem\u003e(\u003ca href=\"https://drive.google.com/file/d/1oSgHtIm0NpQIZKaDYs9VdePl0VIlkmv_/view?usp=sharing\"\u003eSlide\u003c/a\u003e)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e2021 PyCon APAC - \u003ca href=\"https://www.youtube.com/watch?v=dKjLgk_BmEg\"\u003eRelearning Python the right way\u003c/a\u003e (\u003ca href=\"https://docs.google.com/presentation/d/168mwO8cZi_EHIIvCzmNsG3-wYm6Jph6o/edit?usp=sharing\u0026amp;ouid=115990518375034284292\u0026amp;rtpof=true\u0026amp;sd=true\"\u003eslide\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e2019 PySomTum #1 - \u003ca href=\"https://www.youtube.com/watch?v=6S0P9DMZYRQ\"\u003eDon\u0026rsquo;t reinvent the wheel with Django generic\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2018 PyCon Thailand - \u003ca href=\"https://www.youtube.com/watch?v=r3R1VQa4xPk\"\u003eBuilding a sustainable codebase with Type annotations\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2017 Code Mania 101 - \u003ca href=\"https://www.youtube.com/watch?v=6Y5pROPf7BE\"\u003eThe Present, Past, and Future of Asynchronous Programming in Python\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2016 Code Mania 100 - \u003ca href=\"https://www.youtube.com/watch?v=U3R-q6PG1bM\"\u003eToken-based authentication ทำไปทำไม\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"classes\"\u003e\u003cstrong\u003eClasses\u003c/strong\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e2024 - DataRockie\u0026rsquo;s Data Science Bootcamp #10 - \u003ca href=\"https://www.facebook.com/datarockie/videos/7754604551318097\"\u003eIntro to Software Engineering 101\u003c/a\u003e (\u003ca href=\"https://docs.google.com/presentation/d/1e2gYc-hXIzJhav6Vbzwlzh3Buk6acuU5NcK3mNE0WJo/edit?usp=sharing\"\u003eSlide\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e2022 - DataRockie\u0026rsquo;s Data Science Bootcamp #4 - \u003ca href=\"https://www.facebook.com/yothinix/posts/10228068113546472\"\u003eSoftware Engineering Primer: \u003cem\u003eFighting complexity over time with peace\u003c/em\u003e\u003c/a\u003e \u003cem\u003e(\u003ca href=\"https://drive.google.com/file/d/1oTAaRAmwQ-cpN2bHhFMR5sF1LRjYM2qy/view?usp=sharing\"\u003eSlide\u003c/a\u003e)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e2021 - DataRockie\u0026rsquo;s Data Science Bootcamp #3 - Along with the code - \u003cem\u003eTool, Tips and Techniques to make your Python programming life enjoyable (\u003ca href=\"https://docs.google.com/presentation/d/16EmdHbZVqkGvA_boLlr3uLMM1d0A4Eyw/edit?usp=sharing\u0026amp;ouid=115990518375034284292\u0026amp;rtpof=true\u0026amp;sd=true\"\u003eSlide\u003c/a\u003e)\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e2021 - DataRockie\u0026rsquo;s Data Science Bootcamp #2 - Beyond the basic: Modern Python in Action (\u003ca href=\"https://docs.google.com/presentation/d/16Xd0oBP-W6wH48jp2kJE85o7ogsiphT9/edit?usp=sharing\u0026amp;ouid=115990518375034284292\u0026amp;rtpof=true\u0026amp;sd=true\"\u003eSlide\u003c/a\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"certificates\"\u003e\u003cstrong\u003eCertificates\u003c/strong\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e2024 - Dagster Labs - \u003ca href=\"https://courses.dagster.io/certificates/k0gsshpudl\"\u003eDagster \u0026amp; dbt\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2023 - Dagster Labs - \u003ca href=\"https://courses.dagster.io/certificates/qjuzth3qds\"\u003eDagster Essentials\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2021 - The LeSS Company B.V. - Certified LeSS Basics\u003c/li\u003e\n\u003cli\u003e2021 - Scrum Alliance - \u003ca href=\"https://bcert.me/snczxxvct\"\u003eCertified ScrumMaster® (CSM®)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2021 - Coursera - \u003ca href=\"https://www.coursera.org/account/accomplishments/verify/74MP6C7WLRGX\"\u003eBuild a Modern Computer from First Principles: From Nand to Tetris (Project-Centered Course)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e2019 - Coursera - \u003ca href=\"https://www.coursera.org/account/accomplishments/specialization/K799H4HY8PDV\"\u003eDeveloping Applications with Google Cloud Platform Specialization\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"contact\"\u003e\u003cstrong\u003eContact\u003c/strong\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.facebook.com/writepythontoscarecow\"\u003eFacebook Page\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://twitter.com/yothinix\"\u003eTwitter\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.linkedin.com/in/yothinx/\"\u003eLinkedIn\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","title":"About Me!"},{"content":"ต้องเล่าย้อนกลับไปก่อนว่าประมาณช่วงอาทิตย์ก่อนผมไปเห็นเว็บนี้ในทวิตครับ https://dontasktoask.com/th/ ซึ่งมันก็ติดอยู่ในใจอยู่ซักพักนึงเลย เพราะมีหลายเหตุการณ์ในชีวิตมากที่ผมเจอคำถามแบบนี้ แต่ก็ไม่รู้จะอธิบายยังไง\nยิ่งพอเรามาอยู่ในสถานการณ์ที่ต้อง Work From Home กันหมดและต้องเปลี่ยนรูปแบบการสื่อสารมาอยู่บน Text, Voice (Discord) มากขึ้น วิธีการถามหลายๆ อย่างที่เคยใช้ได้ ก็ไม่ค่อยเวิร์ค ช่วงอาทิตย์ที่ผ่านมาผมเลยพยายามสังเกตุตัวเองเหมือนกันว่า “เราตอบคำถามยังไง” ก็เลยค้นพบ Set of practice ที่ผมใช้มาซักพักละ เลยออกมาเป็นบล็อกนี้ และต้องบอกก่อนว่าหลายๆ อย่างผมก็ไม่ได้คิดเองเลย แต่น่าจะเกิดจากการไปอ่าน ไปเรียน หรือได้ยินมา เลยต้องสารภาพตามตรงว่า จำไม่ได้จริงๆ ว่าไปรู้เทคนิคนี้มาจากไหนครับ\n🤔 ถามยังไงให้ง่ายกับคนตอบ เทคนิคแรกผมจำมันได้แม่นเพราะว่า หัวหน้าคนแรกๆ ผมเป็นคนสอนผมเองเรื่องนี้และเป็นเรื่องที่จำกันได้แทบจะทั้งทีม เพราะถ้าถามไม่ตรง Format นี้จะโดนไล่ให้มาประกอบคำถามเป็น Format นี้ใหม่ โดย Format นี้แบ่งเป็น 3 หัวข้อหลักเวลาเราจะถามคือ\nกำลังทำอะไรอยู่ เกิดอะไรขึ้น เราคาดหวังว่ามันจะเป็นยังไง เดี๋ยวผมจะลองยกตัวอย่างก่อนที่จะเข้า Format กับหลังปรับ Format แล้วนะครับ\nBefore: ทำไมมันมีให้เลือกแค่ support เองอ่ะ After: ผมกำลังใช้ admin user ทำการสร้าง user ใหม่ ทำไมในระบบผมถึงมีให้เลือกประเภท user แค่ support นะ ทั้งๆ ที่ user ผมควรสร้างได้ทุกแบบสิทั้ง admin, support, finance ซึ่งถ้าเราสังเกตุดีๆ จะค้นพบว่า เห้ยนี่มันรูปแบบเดียวกับ AAA Pattern เวลาเราเขียน Unit Test เลยนี่น่า สำหรับใครที่ไม่รู้เคยได้ยิน AAA Pattern มาก่อนนะครับ มันคือรูปแบบการเขียนโค้ดของตัว Unit test ให้ออกมาอยู่ใน Structure ที่เราสามารถมองแว็บเดียวแล้วเข้าใจได้เลย โดยแทนที่เราจะเขียนเทสโค้ดออกมาเป็นก้อนๆ เราจะแบ่งเป็น 3 กลุ่มใหญ่ๆ แล้วขั้นด้วย Blank line เป็น\nArrange — การ setup ก่อนที่จะทำการเทสเช่นสร้าง database, mock request ฯลฯ Act — การเรียกระบบที่เราสนใจ ส่วนใหญ่เป็นการ call function/method Assert — การทดสอบว่าสิ่งที่คืนมาจากระบบเป็นไปอย่างที่เราคาดหวังไว้ เหมือนข้างบนเลยใช่มั้ยครับ นี่แหละครับคือสาเหตุที่ทำไม ถ้าเราถามคำถามโดยวาง Format ไว้มันถึงง่ายกับคนตอบ เพราะเราจะรู้คำตอบล่วงหน้าตั้งแต่แรกเลยว่ามันจะเกิดอะไรขึ้น ซึ่งมันทำให้ Scope ปัญหาให้แคบลงได้เยอะและไม่ค่อยหลงประเด็นหรือต้องมาสัมภาษณ์ต่อว่าเกิดตอนไหนด้วยครับ\n🤗 ตอบยังไงให้ง่ายกับคนถาม ถึงแม้ว่าคำถามจะถูก Format มาแล้วก็ตาม แต่สิ่งนั้นก็ไม่ได้รับประกันว่าทั้งสองฝ่ายจะเข้าใจตรงกันเสมอไปครับ เพราะฉะนั้นในฝั่งคนตอบผมมี 2 Practice ที่จับขึ้นมาได้ในช่วงอาทิตย์ที่ผ่านมาครับ\nอย่างแรกเลยคือ บริบท (context) หลายๆ ครั้งที่คนที่มาถามเรา ไม่ได้มี Knowledge Domain ที่เรามีและเราจะเจอสถานการณ์ที่คนถาม ถึงแม้จะใช้ Format ว่ากำลังทำอะไรอยู่แล้ว แต่เราจะสัมผัสได้ว่ามีการใช้ พระเอก ใน Context นั้นปนๆ กันไปหรือสลับกันไปมา ซึ่ง สำหรับคนตอบมันคือ สัญญาณว่าคนถามยังไม่เข้าใจ context ของสิ่งที่ตัวเองถามทั้งหมด\nเพราะฉะนั้นในฐานะคนตอบ ถ้าเราสัมผัสได้ว่าคนถามอยู่คนละ Context กับเราแล้ว สิ่งแรกที่ควรทำคือ “พาเขามาอยู่ใน Context เดียวกันก่อนครับ” ซึ่งจะใช้เวลานานแค่ไหนขึ้นอยู่กับว่า Scope ของคำถามใหญ่แค่ไหนด้วย แต่มันสำคัญที่ต้องปูพื้นฐานก่อน เพื่อที่จะลดคำถามที่ตามมาในช่วงที่เราตอบคำถามจริงๆ ไปได้ครับ\nอีกเทคนิคหนึ่งคือ หลังจากที่เราตอบคำถามเสร็จไปแล้ว เราถ่ายทอด สิ่งที่เราเข้าใจ/ความเห็น ไปให้คนถามจนหมดแล้ว ผมจะถามคำถามอีกหนึ่งคำถามกลับไปหาคนถามในฐานะคนตอบคือ\n💬 “ผมตอบคำถามคุณไปรึยังนะ”\nที่ต้องถามคำถามนี้ในจุดนี้ เพราะหลายครั้งเราในฐานะคนตอบก็เผลอปู Context อยู่แล้วพาออกทะเลไปไกลมาก จนอาจจะลืมไปได้ว่าเราต้องตอบคำถามอะไรเค้านะ ซึ่งคำถามนี้จะช่วยให้คนถามพาเรากลับมาสู่ประเด็นจริงๆ ได้ครับ\nประโยชน์อีกข้อของคำถามนี้คือ มันช่วยเช็คความเข้าใจในฝั่งของคนถาม หลังจากได้ยินคำตอบทั้งหมดไปด้วยว่า ที่เราพูดไปมันมีประโยชน์กับเค้ามั้ย หรือเข้าใจตรงกับเราจริงๆ รึเปล่า ซึ่งจะเป็นโอกาสให้คนถามหยุดคิด และอาจจะถามขึ้นมาต่อในจุดที่ยังไม่เข้าใจอยู่ หรืออาจจะไม่ถามในตอนนั้น แต่เดินกลับไปแล้วคำถามนี้มันติดอยู่ในหัวอยู่จนทำให้คิดอะไรได้บางอย่างที่ขาดไป ก็เป็นได้\nเทคนิคก็จะประมาณนี้ครับ ที่ผมสังเกตุเห็นกับตัวเองในหนึ่งสัปดาห์ที่ผ่านมา สิ่งสุดท้ายที่อยากฝากคือ ทุกครั้งที่เราถามหรือตอบคำถาม “พยายามเอาใจเขามาใส่ใจเรา” ครับ สำหรับผมถ้ามีคนมาขอความช่วยเหลือ ผมจะคิดเสมอว่าอีกฝั่งเค้าพยายามหาทางออก จนสุดความสามารถของตัวเองละ ถึงจะมาขอความช่วยเหลือ เพราะมันต้องรวบรวมความกล้ามาก ในการมาถามคำถามครับ\nในขณะที่ผมถ้าเป็นคนที่ถามก็จะคิดเสมอว่าอีกฝั่งเค้าสละเวลามาช่วยเราแล้ว เค้าอาจจะเลือกไม่ช่วยเราก็ได้ แต่เค้าเลือกที่จะมาช่วยเราแล้ว ไม่ว่าสุดท้ายแล้วคำตอบนั้นมันจะช่วยแก้ปัญหาเรารึเปล่า อย่าลืมขอบคุณสำหรับความช่วยเหลือเสมอครับ\n","permalink":"https://yothinix-com.pages.dev/how-to-ask/","summary":"\u003cp\u003eต้องเล่าย้อนกลับไปก่อนว่าประมาณช่วงอาทิตย์ก่อนผมไปเห็นเว็บนี้ในทวิตครับ \u003ca href=\"https://dontasktoask.com/th/\"\u003ehttps://dontasktoask.com/th/\u003c/a\u003e ซึ่งมันก็ติดอยู่ในใจอยู่ซักพักนึงเลย เพราะมีหลายเหตุการณ์ในชีวิตมากที่ผมเจอคำถามแบบนี้ แต่ก็ไม่รู้จะอธิบายยังไง\u003c/p\u003e\n\u003cp\u003eยิ่งพอเรามาอยู่ในสถานการณ์ที่ต้อง Work From Home กันหมดและต้องเปลี่ยนรูปแบบการสื่อสารมาอยู่บน Text, Voice (Discord) มากขึ้น วิธีการถามหลายๆ อย่างที่เคยใช้ได้ ก็ไม่ค่อยเวิร์ค ช่วงอาทิตย์ที่ผ่านมาผมเลยพยายามสังเกตุตัวเองเหมือนกันว่า “เราตอบคำถามยังไง” ก็เลยค้นพบ Set of practice ที่ผมใช้มาซักพักละ เลยออกมาเป็นบล็อกนี้ และต้องบอกก่อนว่าหลายๆ อย่างผมก็ไม่ได้คิดเองเลย แต่น่าจะเกิดจากการไปอ่าน ไปเรียน หรือได้ยินมา เลยต้องสารภาพตามตรงว่า จำไม่ได้จริงๆ ว่าไปรู้เทคนิคนี้มาจากไหนครับ\u003c/p\u003e\n\u003ch2 id=\"-ถามยงไงใหงายกบคนตอบ\"\u003e\u003cstrong\u003e🤔 ถามยังไงให้ง่ายกับคนตอบ\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eเทคนิคแรกผมจำมันได้แม่นเพราะว่า หัวหน้าคนแรกๆ ผมเป็นคนสอนผมเองเรื่องนี้และเป็นเรื่องที่จำกันได้แทบจะทั้งทีม เพราะถ้าถามไม่ตรง Format นี้จะโดนไล่ให้มาประกอบคำถามเป็น Format นี้ใหม่ โดย Format นี้แบ่งเป็น 3 หัวข้อหลักเวลาเราจะถามคือ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eกำลังทำอะไรอยู่\u003c/li\u003e\n\u003cli\u003eเกิดอะไรขึ้น\u003c/li\u003e\n\u003cli\u003eเราคาดหวังว่ามันจะเป็นยังไง\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eเดี๋ยวผมจะลองยกตัวอย่างก่อนที่จะเข้า Format กับหลังปรับ Format แล้วนะครับ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eBefore\u003c/strong\u003e: ทำไมมันมีให้เลือกแค่ support เองอ่ะ\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAfter\u003c/strong\u003e: ผมกำลังใช้ admin user ทำการสร้าง user ใหม่ ทำไมในระบบผมถึงมีให้เลือกประเภท user แค่ support นะ ทั้งๆ ที่ user ผมควรสร้างได้ทุกแบบสิทั้ง admin, support, finance\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eซึ่งถ้าเราสังเกตุดีๆ จะค้นพบว่า เห้ยนี่มันรูปแบบเดียวกับ AAA Pattern เวลาเราเขียน Unit Test เลยนี่น่า สำหรับใครที่ไม่รู้เคยได้ยิน AAA Pattern มาก่อนนะครับ มันคือรูปแบบการเขียนโค้ดของตัว Unit test ให้ออกมาอยู่ใน Structure ที่เราสามารถมองแว็บเดียวแล้วเข้าใจได้เลย โดยแทนที่เราจะเขียนเทสโค้ดออกมาเป็นก้อนๆ เราจะแบ่งเป็น 3 กลุ่มใหญ่ๆ แล้วขั้นด้วย Blank line เป็น\u003c/p\u003e","title":"ถามยังไงให้ง่ายกับคนตอบ ตอบยังไงให้ง่ายกับคนถาม"},{"content":"ช่วงปีใหม่ผมมีเวลาไปเรียนคอร์ส The Ultimate Go Series ของพี่ยอดซึ่งจากใจคนที่ดู Go อยู่ห่างๆ ผมบอกได้เลยว่าคอร์สนี้สอนได้ครบเครื่องมากในเวลาไม่กี่ชั่วโมง แต่นั่นไม่ใช่ประเด็นครับ ประเด็นคือตอนคอร์ส 2 ที่กำลังเรียนเรื่อง API พี่ยอดใช้ HTTP Client ที่รันจาก Plain-text query เลยบน VSCode ซึ่ง ส่วนตัวผมเคยใช้อะไรคล้ายๆ กันบน Intellij เวอร์ชั่นหลังๆ แต่ก็ยังไม่ค่อยคลิก\nแต่ก็จังหวะพอดีที่คอร์สนี้ผมเรียนอยู่บน emacs ผมที่ค่อยๆ ใช้งานหนักขึ้นเรื่อยๆ เพื่อให้ตอบโจทย์การใช้งานที่สุด โพสนี้เลยจะเล่าว่าผมใช้ Emacs REST cilent ยังไง แล้วก็จะเปรียบเทียบ use case เดียวกันเทียบกับ REST client บน Intellij กับ VSCode ด้วยครับ\nInstalling สำหรับ emacs สามารถโหลดจาก MELPA ได้จาก package ชื่อ restclient ครับ แต่ถ้าใครใช้ Doom ก็เพียงแค่เปิด option rest ; Emacs as a REST client ในไฟล์ init.el แล้วสั่ง doom reload ก็พร้อมใช้งานแล้วครับ\nBasic Usage วิธีการใช้งานของ restclient ทั้งสามเจ้าที่ผมพูดถึงข้างต้นจะคล้ายๆ กันหมดครับ คือให้เราสร้างไฟล์นามสกุล http ขึ้นมาหลังจากนั้นเราก็เขียน Request ลงไปครับ เหมือนตัวอย่างนี้\nPOST http://localhost:8081/todos Authorization: Bearer token Content-Type: application/json { \u0026#34;text\u0026#34;: \u0026#34;test request\u0026#34; } ซึ่งเราจะเห็นได้ว่ามันจะมีส่วนประกอบหลักๆ อยู่ 4 ส่วนคือ\nHTTP Method — ตรงนี้เราจะใส่เป็น GET, POST, PUT, PATCH, DELETE แล้วแต่เราเลย HTTP Endpoint — เป็น URL ที่เราจะไป consuming REST service ครับ Request Header (Optional) — ตรงนี้เป็นส่วนที่เราจะใส่ Request header เช่น Authorization หรือ Content-Type เป็นต้น ถ้าใส่ตัวใหม่ก็เคาะบรรทัดใหม่ แต่มีข้อแม้ว่าต้องติดกับบรรทัดที่เป็น Method + endpoint เสมอครับ Request Body (Optional) — ตัวนี้แล้วแต่ method ครับ แต่ถ้าเราต้องใช้ให้เคาะ เว้นบรรทัดมาจาก header 1 บรรทัด แล้วใส่ body ไปได้เลย แล้วแต่ type ที่เราตั้งไว้ ซึ่งในเคสข้างบนเป็น JSON ครับ พอเราเตรียม Request query เรียบร้อยแล้ว เราสามารถสั่งให้ emacs เรายิง HTTP request ไปตามที่เราเขียนไว้โดยเลื่อน cursor ไปไว้ที่บรรทัด HTTP Method ครับ หลังจากนั้นกด C-c C-c ก็จะเป็นการยิง request ออกไปครับ ซึ่งถ้าเราไม่เคยยิงมาก่อนมันจะเปิด buffer window ของ HTTP Response ให้อัตโนมัติครับ\nซึ่งมันจะโฟกัส cursor มาที่ window ของ response อัตโนมัติด้วยครับ โดยเราสามารถสลับกลับไปที่ window ของไฟล์ http เราได้โดยกด C-x o ครับ\nTricks จริงๆ รู้แค่ข้างบนก็พอใช้งานได้แล้ว 80% ครับ แต่เพื่อความสะดวกสบาย ผมมีทริก 3 อย่างที่ใช้บ่อยมาก หลังจากใช้ emacs REST client ตัวนี้มากซักพัก\nเทคนิคแรกคือ เวลา cursor ของเราดีดมาที่หน้า response แล้วเราต้องคอย Switch กลับบ่อยๆ มันก็น่ารำคาญครับ ซึ่งเทคนิคนึงที่ช่วยได้คือ ให้เราสั่ง request โดยใช้ C-c C-v แทนครับ วิธีนี้จะทำให้มันไม่โฟกัสไปที่ Buffer ของ HTTP Response ถ้าเราต้องการแค่ดูผลลัพธ์เฉยๆ\nเทคนิคที่สองคือ หลายๆ ครั้งการเขียน Request ของเรามันจะมีชื่อซ้ำๆ หรือใช้ Header ซ้ำๆ ใช่มั้ยครับ พอเราไม่อยากเขียนซ้ำหรือต้องแก้หลายที่ ตัว emacs REST client รองรับการสร้าง variable ด้วยในตัวโดย เราสามารถเขียนเป็น\n:base_url = http://localhost:8081 หลังจากนั้น เราก็เอาตัวแปรนี้ไปใช้ได้อย่างเช่นในเคสนี้ผมจะเอาไปใช้กับ endpoint ผมก็สามารถเขียนแบบนี้ได้เลย\nGET :base_url/tokenz ซึ่งนอกจาก การแทนที่ variable แบบง่ายๆ นี้แล้ว เราสามารถทำ multiline variable ได้ด้วย โดยเปลี่ยนจาก = เป็น = \u0026lt;\u0026lt; ซึ่งสามารถไปดูได้ใน GitHub ของ library นี้ได้เลยครับ\nเทคนิคสุดท้ายคือ เป็นเรื่องธรรมดามากที่เราจะมีการป้องกัน API เราด้วย Authentication method แล้วเราต้องมาแปะ token ที่ยิงขอจาก API นึงมาใช้กับ API อื่นๆ ใน emacs REST client ตัวนี้เราสามารถทำได้เหมือนกันครับ โดยทำตามนี้\nใน Request ที่เราทำ Authentication แล้วเราได้ Token กลับคืนมาใน Response ให้เราใส่ Hook ตัวนี้ลงไปหลัง Request ที่เราทำการขอ Token ครับCOPY\n-\u0026gt; run-hook (restclient-set-var \u0026#34;:newtoken\u0026#34; (cdr (assq \u0026#39;token (json-read)))) จะมีจุดสังเกตุอยู่ 2 จุดคือ\n“:newtoken” ตัวนี้คือชื่อตัวแปรที่เราจะเซตให้กับ token ที่เราอ่านขึ้นมาได้ครับ ‘token ตัวนี้เป็น key ใน response body ที่เราจะไปอ่านค่าของ token ขึ้นมาครับ\nนอกจากนั้นจะเป็น function ที่ restclient.el เตรียมมาให้เราในการอ่านค่าจาก Response JSON ครับ\nใน Request ของ protected resource เราสามารถนำตัวแปรนั้นไปใช้ได้เหมือนกับวิธีการใช้ตัวแปรตัวอื่นเลย อย่างเช่นในเคสนี้ผมเอาไปใส่ไว้ใน Authorization header ครับ\nPOST http://localhost:8081/todos Authorization: Bearer :newtoken เพียงแค่นี้เราก็จะสามารถใช้ reuse authentication token กับ request อื่นๆ ได้แล้วครับ ซึ่งจริงๆ ตัว Library นี้ยังมีฟีเจอร์อื่นๆ อีกด้วยครับ สามารถลองกดคีย์ดูได้ ยังมีอีกหลายฟีเจอร์ที่ผมยังไม่ได้ใช้เลย\nComparison with Intellij REST client and VSCode REST client ไหนๆ ก็พูดถึง Emacs แล้วก็ขอเทียบกับ REST client แบบเดียวกันของ Intellij กับ VSCode เลยละกันว่ามันมีข้อดีข้อเสียต่างกันยังไงบ้าง\nเทียบกัน 3 เจ้า ถ้าไม่นับคีย์ emacs ที่กดง่ายมากในตัวอยู่แล้ว ผมยกให้ VSCode REST client นี่ UX ดีสุดเลยครับ ผมรู้สึกว่าการประกาศตัวแปร กับการใช้งานมันตรงไป ตรงมาดีแต่ที่ชอบที่สุดของตัว VSCode คือวิธีการที่มันดึงค่ามาจาก Response นี่ ง่ายที่สุดในทั้ง 3 เจ้า แล้วก็ตรงไปตรงมาที่สุดแล้วครับ โดยแค่บอกชื่อ request name แล้วก็แกะ body ออกมา bind ใส่ variable จบ ซึ่งมันควรจะแค่นี้จริงๆ ครับ\nในส่วนของ Intellij REST Client ผมว่าข้อดีคือมัน Integrate กับ ecosystem ของ Jetbrain ได้เนียนจนคนที่ใช้อยู่แล้ว จะไม่รู้สึกว่ามันขัดเลยอย่างเช่นปุ่มกด run request รวมถึง Response ที่หน้าตาไม่ต่างกับ test runner ที่คุ้นเคยกันอยู่แล้ว อาจจะมี function ที่เวิ่นเว้อหน่อยในการแกะ response ออกมา แต่ผมว่าก็ยังอ่านง่ายกว่าและตรงไปตรงมากว่า emacs ครับ\nข้อเสียหลักๆ ของ Intellij REST cilent คือการที่เราต้องประกาศ environment แยกไว้อีกไฟล์นี่แหละครับ ส่วนตัวผมรู้สึกว่ามันขัดใจมาก (หรือถ้ามันประกาศไว้ในไฟล์เดียวได้บอกผมหน่อยนะครับ) อีกข้อเสียนึงที่เป็นส่วนหนึ่งให้ผมเลิกใช้ตัวนี้ไปคือมันจะเก็บ Response ไว้ในไฟล์เป็น default ครับ ซึ่งพอเราเทสบ่อยๆ มันก็สร้างไฟล์ response ออกมาบานมา แล้วต้องมาคอยนั่งไล่ลบใน .idea เราที่บวมขึ้นเรื่อยๆ ครับ\nVerdict สุดท้ายแล้ว ผมรู้สึกว่าเรามาถึงยุคที่การเก็บ HTTP Request query เป็น Plain text นี้มันดูแลง่ายกว่าสมัยก่อนมากๆ ครับ เพียงแค่ยัดลง git เราก็จะ maintain ตัวนี้ได้ยาวๆ เป็น executable document ที่แท้จริง แล้วจะเห็นได้ว่าแทบจะทุก editor/IDE รองรับแล้ว แต่อาจจะแตกต่างกันไปตามสไตล์แต่ละ implementation ของตัวเองครับ ซึ่งในจุดนี้ถ้าทั้งทีมตกลงกันดีๆ ผมคิดว่าน่าจะไม่มีปัญหาอะไร ส่วนใครเอาไปปรับใช้กับตัวเองแล้วเจอเทคนิคอะไรดีๆ ก็แบ่งปันกันได้ครับ แล้วเจอกันใหม่ตอนหน้าครับ\nปล.นอกเรื่องนิดนึงตอนแรกซีรีย์ emacs diary นี้ผมว่าจะเขียนตั้งแต่ Basic ขึ้นไปเรื่อยๆ แต่คิดว่าทำแบบนั้นกว่าจะได้เขียนเรื่องที่อยากเขียน หรือพอมีเรื่องที่จะเขียนมันก็ต่อคิวยาว เพราะฉะนั้นผมเลยเปลี่ยนแนวทางใหม่เป็นลงตามอารมณ์เลยละกันครับ 555\n","permalink":"https://yothinix-com.pages.dev/emacs-rest-client/","summary":"\u003cp\u003eช่วงปีใหม่ผมมีเวลาไปเรียนคอร์ส \u003cstrong\u003e\u003ca href=\"https://skooldio.com/bundles/the-ultimate-go-series\"\u003eThe Ultimate Go Series\u003c/a\u003e\u003c/strong\u003e ของพี่ยอดซึ่งจากใจคนที่ดู Go อยู่ห่างๆ ผมบอกได้เลยว่าคอร์สนี้สอนได้ครบเครื่องมากในเวลาไม่กี่ชั่วโมง แต่นั่นไม่ใช่ประเด็นครับ ประเด็นคือตอนคอร์ส 2 ที่กำลังเรียนเรื่อง API พี่ยอดใช้ HTTP Client ที่รันจาก Plain-text query เลยบน VSCode ซึ่ง ส่วนตัวผมเคยใช้อะไรคล้ายๆ กันบน Intellij เวอร์ชั่นหลังๆ แต่ก็ยังไม่ค่อยคลิก\u003c/p\u003e\n\u003cp\u003eแต่ก็จังหวะพอดีที่คอร์สนี้ผมเรียนอยู่บน emacs ผมที่ค่อยๆ ใช้งานหนักขึ้นเรื่อยๆ เพื่อให้ตอบโจทย์การใช้งานที่สุด โพสนี้เลยจะเล่าว่าผมใช้ Emacs REST cilent ยังไง แล้วก็จะเปรียบเทียบ use case เดียวกันเทียบกับ REST client บน Intellij กับ VSCode ด้วยครับ\u003c/p\u003e\n\u003ch2 id=\"installing\"\u003e\u003cstrong\u003eInstalling\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eสำหรับ emacs สามารถโหลดจาก MELPA ได้จาก package ชื่อ \u003ca href=\"https://github.com/pashky/restclient.el\"\u003erestclient\u003c/a\u003e ครับ แต่ถ้าใครใช้ Doom ก็เพียงแค่เปิด option \u003ccode\u003erest ; Emacs as a REST client\u003c/code\u003e ในไฟล์ init.el แล้วสั่ง \u003ccode\u003edoom reload\u003c/code\u003e ก็พร้อมใช้งานแล้วครับ\u003c/p\u003e","title":"ยิง request แบบไม่มีสะดุดด้วย emacs REST client"},{"content":"Year In Review นี่เขียนครั้งสุดท้ายตั้งแต่ปี 2019 เลย ปีที่แล้วตั้งท่าว่าจะเขียนสุดท้ายก็ไม่ได้เขียน ปีนี้เลยขอเอาใหม่ เหมารวบ 2 ปีเลยละกัน\n📚 Live \u0026amp; Learn มันมีช่วงเวลาที่เราตั้งคำถามกับตัวเองว่า เราอยากจะทำอะไรกันแน่ แล้วมันก็ตอบไม่ค่อยได้ แต่สิ่งที่ช่วยให้ตอบคำถามนี้ได้เร็วขึ้นคือการต้องเปลี่ยนงานแบบกระทันหันตอนช่วงต้นปี 2020 เลยทำให้ทุกๆ อย่างที่เคยคิดไว้ต้องเปลี่ยนไปหมดเลย แล้วเริ่มนับ 1 ใหม่\nช่วงปี 2020 แทบจะทั้งปี เป็นช่วงที่ตั้งคำถามเรื่องนี้กับตัวเองจริงจังมากๆ เพราะพอมันต้องมาอยู่ใน environment ใหม่อะไรที่เคยคิดว่าทำแล้วเวิร์คมันไม่เวิร์ค โลกบางครั้งก็ไม่ได้หมุนในจังหวะที่เราคุ้นเคย เป็นปีที่ต่อสู้กับ Self-esteem ตัวเองหนักมาก เรียกได้ว่าพังทลายเลย\nจำได้ว่าช่วงปลายๆ ปี 2020 เป็นช่วงที่ฟื้นกลับมาละ แล้วกำลังตามหาสิ่งยึดเหนี่ยวจิตใจจนได้ไปเรียน Math for Working Programmer เลยได้กลับมาสนใจ Foundation ของการโปรแกรมหลายๆ อย่างที่ต้องยอมรับจริงๆ ว่าอยู่รอดมาได้หลายปีโดยไม่ได้ศึกษา และมันถึงเวลาที่ต้องศึกษาแล้ว ประกอบกับช่วงนั้นย้ายที่ทำงานอีกรอบพอดี เลยได้ทดลองอะไรใหม่ๆ หลายอย่างเลย\nพอจิตใจตัวเองกลับมาดีแล้วอะไรๆ มันก็กลับมาดีตาม มีพลังทั้งไปเรียนเยอะมาก (How to Design Program, NAND2Tetris, Programming Languages Part A, Certified ScrumMaster) และไปสอนก็เยอะมากเช่นกัน แล้วมันทำให้ภาพที่ตัวเองตามหาว่าอยากทำอะไรมันชัดเจนขึ้นเรื่อยๆ จนตอนนี้ตอบได้เต็มปากว่าเรื่องที่สนใจคือ Programming Language (PL) และยังตื่นตาตื่นใจทุกครั้งที่เจอ paradigm ใหม่ๆ ในหลายๆ ภาษาครับ\n👨‍👩‍👧‍👦 Refactoring Club สิ่งหนึ่งที่ทำให้ตัวเอง Shift ความสนใจจาก Software Engineering มา PL ส่วนหนึ่งเพราะ ความล้มเหลวจากการทำ Refactoring Club รอบนี้ด้วย ซึ่งมันเริ่มด้วยความตั้งใจมากๆ ในช่วงที่มีพลังสูงมาก แต่หลังจากที่ทำไปได้ 4 session ในช่วง 2 เดือนก็ยอมรับตามตรงเลยว่าหมดพลังเพราะงานอื่นๆ ที่ถาโถมเข้ามา\nซึ่งผมเสียใจมากไปพักนึงเลย ที่ไม่สามารถทำให้มันไปได้จนถึง 10 session อย่างที่ตั้งใจไว้ มันมีหลายครั้งตลอดปี 2021 ที่ผมก็คิดว่า อยากจะกลับไปพูดคุยกับคนใน Club แต่ก็ไม่กล้ามาจนถึงวันนี้ แต่ถึงจะเสียใจแค่ไหน สำหรับ Software Engineering ผมยังหาโอกาสจะไปถ่ายทอดเท่าที่จะทำได้ ซึ่งโชคดีมากที่พี่ทอยชวนไปสอนในช่วง 2 ปีที่ผ่านมาเลยได้ปล่อยของออกไปบ้าง แต่ก็ยังไม่ถึงกับที่ตั้งใจไว้กับ Refactoring Club\n👨‍💼 Java and IT Enterprise ผมเขียน Python มาตลอดชีวิต มีโอกาสต้องไปทำหน้าบ้านบ้างตามหน้าที่ แต่หลักๆ ก็โฟกัสอยู่กับหลังบ้านกับ Python นั่นทำให้ Python เป็น safe-zone ผมมาตลอดหลายปี จนกระทั่ง 2020 ต้องเปลี่ยนงานกระทันหัน แล้วจับพลัดจับพลูมาเขียน Java ซึ่งไม่เคยเขียนเลยตั้งแต่เรียนปี 2 ในมหาลัย ซึ่งถ้ามามองย้อนกลับไปในช่วงพยายามปรับตัวกับ Idiom กับ Semantics ของ Java นี่ก็ทำให้ได้รู้อะไรหลายอย่างเลย ที่ควรทำและไม่ควรทำ และเข้าใจวิธีคิดอีกโลกด้วย แต่ก็ไม่ได้อยากอยู่โลกนี้ไปตลอดนะ\nอีกสิ่งคือ ผมทำงานในบริษัทไม่ใหญ่มากมาตลอด และด้วยความที่ทีมมันเล็ก ทำให้พอย้ายงานมาอยู่ใน Enterprise เลยค้นพบว่า Autonomy ของเรามันลดลงมากๆ มากจนหลายๆ ครั้งอึดอัด จนต้องต่อสู้กับจิตใจตัวเองว่า เรามาทำอะไรที่นี่นะ เลยเป็นที่มาของเรื่อง Self esteem ข้างบนนั่นแหละ\nสุดท้ายแล้ว ถ้าจะมีอะไรที่เป็นเหตุผลให้ไปทำงานในทุกๆ วันนอกจากจะไปสู้รบปรบมือกับโค้ดชาวบ้านที่สามารถแคปมาวิพากษ์วิจารณ์ได้ไม่เว้นแต่ละวัน ผมว่าผมโชคดีที่ผมมีทีมที่ยังทำงานด้วยสนุกอยู่ และยังได้ทำงานกับคนที่เก่งหลายๆ คนที่ยังได้ให้เรียนรู้อะไรใหม่ๆ อยู่บ้าง\n🏖 Finding Peace ช่วง 2 ปี 2020-2021 นี่เป็นช่วงเวลาที่ผมมีปัญหากับการตามหาความสงบมากๆ ส่วนหนึ่งเพราะการต้องออกจาก Safe-zone แล้วไปอยู่ในสภาพแวดล้อมที่ไม่คุ้นเคย ทำให้หลายๆ ครั้งอยากจะถอยออกมาตั้งหลัก หายใจลึกๆ ก่อนที่จะเดินต่อ ในโลกที่แม่งหมุนเร็วชิปหาย\nแต่มันตลกตรงที่ว่า ในช่วงเวลาที่ผมแทบจะทนไม่ไหวตลอด 2 ปีที่ผ่านมา มันจะมีเหตุการณ์ให้ผมต้องหลุดออกมาจากตรงนั้นออกมาหายใจ โดยที่ผมไม่ได้เลือกเองทุกครั้ง เช่นในปี 2020 ผมมีเหตุให้ต้องไปใช้ชีวิตอยู่บ้านเกิดแฟนที่อรัญประเทศอาทิตย์นึงเต็มๆ แล้วเว้นไปหนึ่งอาทิตย์ก็มีเหตุให้ต้องกลับไปใช้ชีวิตที่บ้านตัวเองที่บุรีรัมย์ ช่วงเวลานั้นเป็นครั้งแรกตั้งแต่อยู่กรุงเทพฯ มาตั้งแต่เรียนมหาลัยเลยที่มีความคิดว่า กลับไปอยู่บ้านมันก็ดีเหมือนกันนะ Pace มันวิ่งช้ากว่าเยอะมากเลย\nอีกครั้งนึงก็ปีนี้ซึ่งผมหมกมุ่นกับคอนเซปของการปิดเทอมมากๆ (หนังสือหลายๆ เล่มจะชอบพูดว่า Mini-retirement) ซึ่งประกอบกับปีนี้มันรู้แล้วว่ามีเรื่องอยากจะไปเรียน อยากจะไปอ่านหนังสือและหลายคอร์สที่เรียนไม่ไหว เพราะต้องทำงานไปด้วย เลยอยากจะออกไปนั่งเรียนมันยาวๆ ให้รู้แล้วรู้รอด ให้ Enlightenment มันเกิด แต่ปีนี้ก็โดนซัดด้วยต่อมน้ำเหลืองอักเสบจนเข้าโรงพยาบาล แล้วต้องพักยาวๆ ไปสองอาทิตย์ติดกัน\n⏰ Time \u0026gt; Money ต่อจากเรื่องข้างบนคือ พอเราอยากจะหาความสงบ มันก็กลายๆ ว่ามันต้องการหาเวลา ให้มากขึ้น ทำให้ตลอด 2 ปีที่ผ่านมาเลือกที่จะไม่รับงานนอกอะไรเพิ่มอีกเลย แต่ต้องบอกว่าจะไม่มาถึงจุดนี้เลย ถ้าทั้งงานหลักและงานเสริมที่ดูแลค้างมาอยู่ไม่ support ให้อยู่ได้โดยไม่ต้องขวนขวายหาเงินมากไปกว่านี้\nซึ่งที่พยายามหลักๆ คือพยายามเลิกงานให้ตรงเวลา หาเวลามาดูท้องฟ้าตอนเย็นๆ ห้าโมงหกโมง ครั้งสุดท้ายที่ผมเคยโหยหา Moment แบบนี้คือตอนย้ายจากทำงานเลิกสี่ทุ่มมาเลิกเวลาเหมือนชาวบ้าน ซึ่งผมบอกได้เลยว่า ช่วงเวลาที่ได้ดูท้องฟ้ามันมืดลงแต่ละวันนี่มันดีต่อใจมากเหลือเกิน และมันช่วยชาร์จพลังเราในแต่ละวันให้พร้อมสำหรับวันต่อไปมากๆ\nส่วนเรื่องเงินปี 2020 อาจจะมีหนี้อยู่บ้างเพราะต้องหา Mac มาใช้เองไม่ได้ใช้ของบริษัทอีกต่อไป แต่พอปี 2021 พอปลดล็อกแล้วก็ไม่เหลือหนี้ระยะยาวเลย และไม่มีแผนจะสร้างเร็วๆ นี้ด้วยเพราะยังอยากคล่องตัวอยู่ แต่ถึงแม้จะไม่มีทรัพย์สินติดตัวเป็นชิ้นเป็นอัน แต่มีทรัพย์สินเป็นตัวเลขกระจายไปใน ETF, MF, SET, Crypto ฯลฯ บ้างให้มันไม่ขี้เกียจเกินไป\n🐤 Gatuk อยากจะพูดถึงกะตั๊กหน่อย เพราะว่าปี 2020 - 2021 มันไม่ใช่ช่วงที่ง่ายเลย มันมีหลายช่วงที่หนักจนรับไม่ไหว มันมีหลายช่วงที่ใกล้จะบ้าแล้ว หรือหลายความคิดก็สุดโต่งเกินไป ถ้าไม่ได้มีกะตั๊กคอยเตือนสติไว้ ตอนนี้ก็จินตนาการไม่ออกเลยว่าตัวเองจะเป็นไงบ้าง\nกะตั๊กไม่ใช่ว่าจะเออ ออทุกเรื่องด้วยนะ เป็นคนที่มีความคิดของตัวเองและโตมาในโลกที่ต่างกันโดยสิ้นเชิงก่อนจะมาเจอกัน ทำให้การได้เห็นโลกในมุมมองของกะตั๊กอะ มันทำให้เรารู้ว่า บางทีเราก็เห็นแก่ตัวเกินไป หลายครั้งก็มีคนลำบากกว่าเราตั้งเยอะ และช่วงดึงกลับมาสู่โลกแห่งความเป็นจริงให้ยังเป็นผู้เป็นคนอยู่บ้าง\n📝 Footnotes กลับมาอ่านหนังสือแล้วหลังจากที่ 2019 - 2020 นี่อ่านน้อยมาก 2021 นี่อ่านเยอะมาก แต่ถ้าชอบสุดยังยกให้ The Phoenix Project ที่เพิ่งมีเวลาอ่านซักที งานอดิเรกไหลไปตามอารมณ์เคยมีช่วงที่บ้า Chess มากๆ ช่วงที่กลับมาบิน Flight Sim จริงจัง ช่วงประกอบ Keyboard ชงชา ส่วนตอนนี้มีความสุขกับการสะสม Clone Trooper อยู่ ปี 2020 ไม่ได้พูดงานอะไรเลยหลังจาก 2019 ที่จัด PySomtum มาให้ตัวเองพูด 2021 ไปพูดที่ PyCon APAC 2021 ซึ่งนอกจากได้ไปพูดและจัดงาน ได้ไปร่วม Panel discussion: Future of Python กระทบบ่ากับคนที่เราเคยได้แต่เขียนข่าวถึงในเพจ ปีนี้ลดการทำเพจไปอย่างมีนัยยะสำคัญ ถึงแม้จะยังอยู่กับ Python community แต่ก็ไม่ค่อยได้แชร์อะไร แต่กลับกันคือ กลับมาเขียนบล็อกจริงจังมากขึ้นและ settled กับ Hashnode แล้วหลังจากหนี Medium ออกมา สิ่งที่คุ้มที่สุดที่เสียตังค์ในช่วง 2 ปีที่ผ่านมาคือ ประกันสุขภาพแบบ IPD ซึ่งถ้าไม่มีตัวนี้บอกเลยว่าที่เข้าโรงพยาบาลล่าสุดนี่เสียเกือบแสน แต่นี่คือไม่เสียตังค์แม้แต่บาทเดียว เกมที่เล่นแล้วประทับใจที่สุดในช่วง 2 ปีนี้เป็น Uncharted 4 ซึ่งก็เพิ่งมีโอกาสได้เล่นหลังจากมันออกมาชาติกว่าละ แต่ประทับใจทุกอย่างมันรวมๆ กันไปหมด ปีนี้ไป Conference เยอะมาก ไม่รู้ควรจะขอบคุณ COVID ดีมั้ยที่ทำให้งานต่างๆ จัด Online หมดเลยได้ไปหมดเลยทั้ง PyCascades, PyConBY, PyCon US, DjangoCon EU, TDD Conf และ PyCon APAC ซึ่งหลายๆ งานถ้าจะมีอะไรที่ติดก็คือ Timezone นี่แหละยิ่ง PyCon US นี่เวลานอนที่แท้ทรู ปีนี้จับพลัดจับพลูได้ไปสัมภาษณ์กับ Microsoft APAC กับ Campaign: Code; Without Barriers โอลิมปิกปีนี้ทำให้ค้นพบว่าตัวเองชอบดู High Jump กับ Pole Vault มาก ปีนี้ Relearn flow ในการทำงานของตัวเองทั้งเปลี่ยน Keyboard มาใช้ Ergodox, เปลี่ยน layout มาใช้ Dvorak และล่าสุดเปลี่ยน Text Editor หลักจาก Vim มาเป็น Emacs แต่อีกอย่างที่มีผลมากๆ คือเปลี่ยนมาทำงานจอใหญ่จอเดียว หลังจากต่อสองจอมาหลายปี อยากบันทึกไว้ด้วยว่าปี 2020 เคยจัดงาน Event แล้วไม่มีคนมางานแม้แต่คนเดียว (นอกจาก Speaker) แต่ช่วงนั้นเป็นช่วงที่ COVID เพิ่งมาด้วยแหละ ถึงแม้สองปีนี้จะไม่ค่อยได้ไปเที่ยวแต่ทริปที่ประทับใจสุดคือการเที่ยวในกรุงเทพแล้วไปค้นพบร้าน The Never Ending Summer และแกงเผ็ดเป็ดย่างของเขานี่แหละ สุดท้ายตลอด 2 ปีมานี้เวลามองออกไปนอกหน้าต่างจะคิดถึงอยู่อย่างเดียว IHTFP ","permalink":"https://yothinix-com.pages.dev/2020-2021/","summary":"\u003cp\u003eYear In Review นี่เขียนครั้งสุดท้ายตั้งแต่ปี \u003ca href=\"https://yothinix.blogspot.com/2020/01/2019.html\"\u003e2019\u003c/a\u003e เลย ปีที่แล้วตั้งท่าว่าจะเขียนสุดท้ายก็ไม่ได้เขียน ปีนี้เลยขอเอาใหม่ เหมารวบ 2 ปีเลยละกัน\u003c/p\u003e\n\u003ch2 id=\"-live--learn\"\u003e\u003cstrong\u003e📚 Live \u0026amp; Learn\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eมันมีช่วงเวลาที่เราตั้งคำถามกับตัวเองว่า \u003cem\u003eเราอยากจะทำอะไรกันแน่\u003c/em\u003e แล้วมันก็ตอบไม่ค่อยได้ แต่สิ่งที่ช่วยให้ตอบคำถามนี้ได้เร็วขึ้นคือการต้องเปลี่ยนงานแบบกระทันหันตอนช่วงต้นปี 2020 เลยทำให้ทุกๆ อย่างที่เคยคิดไว้ต้องเปลี่ยนไปหมดเลย แล้วเริ่มนับ 1 ใหม่\u003c/p\u003e\n\u003cp\u003eช่วงปี 2020 แทบจะทั้งปี เป็นช่วงที่ตั้งคำถามเรื่องนี้กับตัวเองจริงจังมากๆ เพราะพอมันต้องมาอยู่ใน environment ใหม่อะไรที่เคยคิดว่าทำแล้วเวิร์คมันไม่เวิร์ค โลกบางครั้งก็ไม่ได้หมุนในจังหวะที่เราคุ้นเคย เป็นปีที่ต่อสู้กับ Self-esteem ตัวเองหนักมาก เรียกได้ว่าพังทลายเลย\u003c/p\u003e\n\u003cp\u003eจำได้ว่าช่วงปลายๆ ปี 2020 เป็นช่วงที่ฟื้นกลับมาละ แล้วกำลังตามหาสิ่งยึดเหนี่ยวจิตใจจนได้ไปเรียน \u003ca href=\"/mathematics-for-working-programmers\"\u003eMath for Working Programmer\u003c/a\u003e เลยได้กลับมาสนใจ Foundation ของการโปรแกรมหลายๆ อย่างที่ต้องยอมรับจริงๆ ว่าอยู่รอดมาได้หลายปีโดยไม่ได้ศึกษา และมันถึงเวลาที่ต้องศึกษาแล้ว ประกอบกับช่วงนั้นย้ายที่ทำงานอีกรอบพอดี เลยได้ทดลองอะไรใหม่ๆ หลายอย่างเลย\u003c/p\u003e\n\u003cp\u003eพอจิตใจตัวเองกลับมาดีแล้วอะไรๆ มันก็กลับมาดีตาม มีพลังทั้งไปเรียนเยอะมาก (How to Design Program, NAND2Tetris, Programming Languages Part A, Certified ScrumMaster) และไปสอนก็เยอะมากเช่นกัน แล้วมันทำให้ภาพที่ตัวเองตามหาว่าอยากทำอะไรมันชัดเจนขึ้นเรื่อยๆ จนตอนนี้ตอบได้เต็มปากว่าเรื่องที่สนใจคือ Programming Language (PL) และยังตื่นตาตื่นใจทุกครั้งที่เจอ paradigm ใหม่ๆ ในหลายๆ ภาษาครับ\u003c/p\u003e","title":"2020 - 2021"},{"content":"ผมรู้จัก The Phoenix Project มานานมากและมันวนเวียนมาเกือบจะได้อ่านหลายรอบ จนกระทั่งเมื่อประมาณกลางเดือนที่แล้ว ผมเพิ่งได้มีโอกาสจะหยิบมันขึ้นมาอ่าน และตั้งแต่ตอนนั้นผมแทบจะวางไม่ลงเลยตลอดระยะเวลาเกือบหนึ่งเดือนที่ผ่านมา และผมแนะนำให้กับทุกคนที่ทำงานใน IT ทั้ง Business และ Engineering ควรอ่านเลยครับ\nThe Phoenix Project เล่าเรื่องผ่านสายตาของ Bill Palmer - Manager ระดับกลางๆ ที่จับพลัดจับพลูถูกเลื่อนตำแหน่งขึ้นมาเป็น VP of IT Operations ใน Part Unlimited บริษัทขายชิ้นส่วนประกอบต่างๆ ของรถยนต์ที่กำลังเดิมพันกับ Phoenix Project ซอฟท์แวร์ตัวใหม่ที่จะช่วยกระตุ้นยอดขายและยกระดับบริการให้ล้ำหน้าคู่แข่งไปได้\nผมพยายามจะสปอยเนื้อหาให้น้อยที่สุดแต่ผมบอกได้ว่า เนื้อเรื่องในหนังสือเล่มนี้มันเข้มข้นมากทุกๆ อย่างมันถาโถมมาอย่างหนักหน่วงและ หลายๆ ครั้งมันตรงกับชีวิตจริง (ถ้าคุณทำงานใน Software Industry มานานพอ) ทุกๆ หน้าที่เรามองผ่านสายตา Bill และพยายามแก้ปัญหาที่เข้ามามันเหมือนกับว่าเราได้ไปนั่งอยู่ตรงนั้น ในห้องประชุม NOC หรือแม้แต่ที่ Production Plant จริงๆ และหลายครั้งตัวผมเองก็คิดไม่ออกว่าจะแก้ปัญหาที่เข้ามาในเรื่องยังไง\nแต่สิ่งที่ผมนับถือที่สุดกับ Bill เลยคือความที่ Bill เป็นคนที่ Humble และ Empowered มาก ซึ่งเราจะเห็นได้จากหลายๆ ครั้งที่เวลาเจอปัญหาแล้ว Bill คิดไม่ออกแต่ทีมช่วยกันคิดออก Bill จะเปลี่ยนโหมดเป็น supporter ไอเดียนั้นทันทีและหลายครั้งก็ช่วย Facilitate ให้ไอเดียนั้นต่อยอดขึ้นไปอีก ในขณะเดียวกันหลายครั้งเราก็จะเห็น Bill จมไปกับความคิด กับไอเดียที่เกิดขึ้นจากเหตุการณ์ต่างๆ ที่ผ่านมาแล้วเกิด Aha! Moment ขึ้นด้วย ซึ่งนอกจาก Bill มีอีก 2 ตัวละครที่ผมอยากพูดถึงคือ Erik (Board Candidate), Brent (Lead Engineer)\nErik ถ้าใครเคยดู Star Wars น่าจะคุ้นเคยกับคำว่า Master Jedi / Padawan ใช่มั้ยครับ ความสัมพันธ์แบบ Mentorship ระหว่างศิษย์กับครูนี่เป็นอะไรที่มีค่ามากๆ ซึ่งผมบอกได้เลยว่า เราจะโชคดีมากๆ ถ้าเรามี Mentor ในช่วงเวลาที่เรากำลังเริ่มอะไรใหม่บางอย่าง\nในเรื่องนี้ Erik นี่เป็น Mentor ที่ผมโคตรจะรักเลย วิธีการที่ Erik พยายามสอนให้ Bill เห็นว่า IT Operation มันไม่ต่างกับ Production Plant นั้นสำหรับผมคือมัน Care Personally เลย ซึ่ง Erik หลายครั้งมากที่จะไม่ให้คำตอบตรงๆ กับ Bill แต่จะให้คำใบ้ไว้ว่ามันจะเกิดอะไรขึ้นต่อไป\nสำหรับผมนี่คือวิธีการสอนที่ดีมาก เพราะมันทำให้เราต้องคิดเยอะมากและพอมันเกิด Aha! Moment ที่เราคิดออก เรื่องนี้มันจะติดอยู่ในหัวเราไปอีกนานเลย และผมเชื่อว่าถ้าใครเคยมี Mentor ลักษณะนี้ในชีวิตหน้าเค้าต้องลอยขึ้นมาหลังจากคุณได้อ่านสิ่งที่ Erik คุยกับ Bill ครับ\nBrent ผมไม่ชอบ Brent ไม่ใช่เพราะว่า Brent มันเก่งจนทุกคนต้องไปขอความช่วยเหลือตลอดไม่ว่าจะเรื่องใหญ่ เรื่องเล็กหรือเป็นคนที่รู้จักระบบแทบจะทุกอย่างที่มีอยู่ในบริษัท แต่เพราะว่าผมเคยเป็นแบบนั้นครับ หรืออาจจะยังเป็นอยู่บางครั้งโดยที่ไม่รู้ตัว\nซึ่งมันทำให้ผมรู้จักคนประเภทนี้ดีมาก เพราะคนประเภทนี้จะงานยุ่งทุกอย่างตลอดเวลา แก้ปัญหาได้ทุกอย่าง (หลายๆ ครั้งก็สร้างปัญหาใหม่ตามมาด้วย) ที่ผมไม่ชอบคือ คนประเภทนี้จะลืมสิ่งที่สำคัญมากๆ ในการทำงานเป็นทีมไปคือการสร้าง Tribe Knowledge กับ Delegate ครับ และสุดท้ายก็จะเป็นคอขวดจนหลายๆ อย่างเดินต่อไปไม่ได้ เพราะต้องรอคนๆ นี้\nท่ามกลางความเข้มข้นของเนื้อเรื่องใน The Phoenix Project จะมี Core Idea อยู่ 2 เรื่องหลักๆ คือ 4 Types of Works และ The Three ways ครับ\nsrc: https://hennyportman.wordpress.com/2016/03/20/book-review-the-phoenix-project-a-novel-about-it-devops-and-helping-your-business-win/\n4 Types of Works ไอเดียแรกคือประเภทของงานครับ ในเรื่อง ด้วยความที่งานมันเข้มข้นแล้วถาโถมมากผมบอกเลยว่า นี่คือตัวช่วยตัวแรกที่ทำให้เราเข้าใจสิ่งต่างๆ ที่เราต้องทำในการทำงานแต่ละวันดีขึ้น ซึ่งกว่า Bill จะคิดออกว่าประเภทไหนเป็นประเภทไหน ก็ต้องเจอสถานการณ์ต่างๆ ก่อนซึ่งมาได้ถูกที่ ถูกเวลามาก โดยงาน 4 ประเภทแบ่งออกเป็น\nBusiness Project — เป็นงานประเภทที่เราได้ requirement มาจาก Business Unit เพื่อตอบโจทย์บางอย่างของบริษัทซึ่งนี่คืองานหลักที่ Business ต้องการจากทีม IT Internal Project — งานประเภทนี้ไม่ได้ Drive มาจาก Business แต่เป็นความรับผิดชอบของทีม IT เองและทีม IT ต้องต่อสู้เพื่อให้ได้ Priority มา ซึ่งถ้าไม่ทำเราก็จะทำงานกันเองลำบากขึ้นเรื่อยๆ งานประเภทนี้เป็นจำพวกเช่น Patch Security, Upgrade Server, Storage, Network ฯลฯ Change — งานอย่างจาก Business Project, Internal Project หลายครั้งมันไม่ได้ทำรอบเดียวจบ เพราะอาจจะทำไปแล้วรู้ว่ามันไม่เวิร์คหรือมีการเปลี่ยน Requirement งานประเภทนี้จะไม่ยิ่งใหญ่เท่า Business Project หรือ Internal Project แต่ก็ต้องทำ เพราะไม่งั้น Business ก็ไปต่อไม่ได้ Unplanned Work — งานข้างบนทั้ง 3 ประเภทที่พูดมา มักจะมี Timeline ที่ Business อยากได้หรือเราไปต่อรองมาครับ แต่เหตุผลหลักที่ทำให้งาน 3 ประเภทข้างบนมัน Delay หรือไม่ได้ทำซักที เพราะงานประเภทที่ 4 นี้ซึ่งก็คืองานที่อยู่ดีๆ ก็โผล่มาครับ อาจจะเป็น Server ระเบิด, ต้องแก้ Security patch ด่วนๆ (อารมณ์เหมือน log4j ล่าสุด) หรือต้องทำ Report ส่ง Audit อะไรแบบนี้เป็นต้นครับ ซึ่งในแต่ละโปรเจ็ค เราก็จะมี Constraint หลักๆ อยู่เช่นเรามีคนที่ทำเรื่องนี้ได้แค่คนนี้จริงๆ และคนนี้ติด Business/Internal Project อยู่ ซึ่งหน้าที่ของ IT Manager เลยคือ พยายามลด Unplanned Work ให้ไปกระทบกับ Constraint ให้น้อยที่สุดเพราะมันไม่ได้สร้าง Business Value เลยโดย Practice ที่ผมเห็นใช้ในหนังสือคือ พยายามจะ Visualize งานต่างๆ ออกมาให้หมด (เพราะก่อนหน้านี้แทบไม่รู้เลยว่าต้องทำอะไรบ้าง รู้แต่ว่าทุกคนยุ่งมากๆ) แล้วจัดการ flow ของมัน ทีมของ Bill เลยเริ่มที่จะเอาอยู่ครับ\nซึ่งเรื่อง Constraint ในหนังสือเรื่องนี้ Refer กลับไปหา Theory of Constraints ของ Dr.Goldratt ในหนังสือ The Goal โดยแบ่งเป็น 5 ขั้นคือ\nหา Constraint ใน Flow ให้เจอก่อน พยายามทำความเข้าใจ Constraint นั้น กันกิจกรรมอื่นๆ ไม่ให้ไปกระทบ Constraint พยายามปรับปรุง Constraint นั้นให้ดีขึ้น หา Constraint ใหม่ต่อไป The Three Ways ส่วนของ The Three Ways ผมขอยก Quote จากหนังสือตอน Erik อธิบาย Bill ถึง The Three Ways มาทั้งก้อนเลยละกันครับ ตรงไปตรงมาดี\n“The First Way helps us understand how to create fast flow of work as it moves from Development into it Operations, because that’s what’s between the business and the customer.\nThe Second Way shows us how to shorten and amplify feedback loops, so we can fix quality at the source and avoid rework.\nAnd the Third Way shows us how to create a culture that simultaneously fosters experimentation, learning from failure, and understanding that repetition and practice are the prerequisites to mastery.”\nErik\nซึ่งก็จะพาเรามาหาไอเดียหลักในเรื่องอีกอย่างนึงคือ IT Operation เนี่ยมันคล้ายกับการจัดการสายการผลิตมาก ลองนึกภาพดูนะครับ สายการผลิตเริ่มจากมี Raw material วิ่งเข้ามาในสายพาน เสร็จแล้วแต่ละส่วนก็ Transform มันให้เป็นชิ้นส่วนบางอย่างเฉพาะทาง แล้วก็จะมีอีกส่วนที่รวมชิ้นส่วนต่างๆ เข้าด้วยกันเพื่อเป็นผลผลิตที่ซับซ้อนกว่า ไปจนจบแล้วได้ชิ้นงานไปขายได้\nงานของ IT Operation อย่างที่เราเห็นข้างบนมีงาน 4 ประเภทวิ่งเข้ามา แล้วเราต้องกระจายไปในทีมต่างๆ ที่ดูแลอยู่ เช่น จะสร้าง Production Server ใหม่ให้กับ Business Project ก็เริ่มจากต้อง Estimate load ขึ้นมา บอกจัดซื้อให้หาของมาให้ (ยังไม่ Cloud) เสร็จแล้ว Engineer ก็ประกอบ Hardware เข้าด้วยกันทั้ง Compute, Network, Storage พอชั้น Hardware เรียบร้อยก็ต้องติดตั้ง Software dependency อย่าง OS, Database, Runtime เรื่อยไปจนถึงติดตั้ง Application แล้วแมพ Network ทำ Smoke tests ก่อนที่จะ Release ให้ลูกค้าใช้งานได้\nภาพจากเกม Assembly Line บน Android\nซึ่งการทำความเข้าใจว่า Operation เราทำงานยังไงนี่เป็นแค่ The First way เท่านั้นครับ ในส่วนของ The Second way จะเป็นเรื่องการ Optimize flow ของเราให้มันมีประสิทธิภาพที่สุดซึ่งก็จะอาศัย Practice หลายๆ อย่างเช่น Theory of Constraint, Managing WIP หรือ Automation มาช่วย เพื่อลด Feedback loop ให้ได้มากที่สุดและ Improve มันจาก Feedback นั้น\nผมเคยมีคำถามนะ ถ้าทุกๆ อย่างมันดีขึ้นแล้ว เอาอยู่แล้ว เราจะทำอะไรได้อีก คำตอบอยู่ใน The Third way ครับ ซึ่งผมพูดเลยว่า “ในช่วงเวลาที่เราคิดว่าทุกอย่างมันดีอยู่ อาจจะมีอะไรบางอย่างมาทำลายสิ่งนั้นได้เสมอ ถ้าเราไม่เตรียมพร้อมตลอดเวลา”\nสิ่งที่จะช่วยลดความเสี่ยงในอนาคตรวมถึงเป็นหลักประกันว่าเราจะเอาอยู่ในอนาคตคือ การที่เราเตรียมพร้อมตลอดเวลาโดยใช้ Practice อย่าง Chaos Engineering, Hackathon, Community of Practice ฯลฯ มาช่วยเพื่อที่จะรับมือการดับไฟในอนาคตครับ\nConclusion ถ้าคุณชอบ The Five Dysfunctions of a Team ของ Patrick Lencioni คุณจะชอบหนังสือเล่มนี้ เพราะนอกจากวิธีการเล่าเรื่องที่ทำให้เราติดได้แบบ Cover to Cover ต้องยอมรับว่า Outcome ที่ได้จากการอ่านหนังสือเล่มนี้มันเยอะมากจริงๆ\nสิ่งที่ผมอยากจะย้ำอีกครั้งคือ หนังสือเล่มนี้ออกมาตอนปี 2013 ในโลกที่ Business เริ่มจะคิดได้ว่า IT สำคัญแค่ไหนกับองค์กร แต่ยังไม่รู้จะทำยังไงและการคิดว่าจะถ่ายทอดมันยังไงยิ่งยากไปใหญ่ และหนังสือเล่มนี้มันทำได้ครับ\nอย่างไรก็ตามถึงแม้ว่าปีนี้จะปี 2021 แล้ว แต่จากประสบการณ์ผมหลายๆ องค์กรยังไม่สามารถที่จะทำให้เกิด The Three Way ได้ครับ แต่ก็ง่ายขึ้นกว่าตอนหนังสือออกมาตอนปี 2013 มาก แต่อุปสรรคในเรื่องนี้จริงๆ ไม่ใช่ Tech ครับ แต่มันอยู่ที่ Culture ซึ่งหลังจากอ่านจบผมเชื่อว่า หนังสือเล่มนี้ทำให้คนเห็นภาพได้ คนที่มีอำนาจตัดสินใจได้เข้าใจภาพได้มากขึ้นว่า IT Operation มันสำคัญกับ Business แค่ไหน\nและสุดท้ายในหนังสือจะมีการพูดถึง Talk ของ John Allspaw กับ Paul Hammond เรื่อง 10+ Deploys Per Day: Dev and Ops Cooperation at Flickr ส่วนตัวผมมีโอกาสไปดูมาแล้วแล้วมันเป็น talk ที่ดีมากๆ อันนึงเลยครับ อยากให้มีโอกาสได้ฟังกัน\n","permalink":"https://yothinix-com.pages.dev/book-review-the-phoenix-project/","summary":"\u003cp\u003eผมรู้จัก The Phoenix Project มานานมากและมันวนเวียนมาเกือบจะได้อ่านหลายรอบ จนกระทั่งเมื่อประมาณกลางเดือนที่แล้ว ผมเพิ่งได้มีโอกาสจะหยิบมันขึ้นมาอ่าน และตั้งแต่ตอนนั้นผมแทบจะวางไม่ลงเลยตลอดระยะเวลาเกือบหนึ่งเดือนที่ผ่านมา และผมแนะนำให้กับทุกคนที่ทำงานใน IT ทั้ง Business และ Engineering ควรอ่านเลยครับ\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://www.amazon.com/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B078Y98RG8/ref=sr_1_1?crid=1JUWYKCN6KSRF\u0026amp;keywords=the+phoenix+project\u0026amp;qid=1639930740\u0026amp;s=books\u0026amp;sprefix=The+phoenix%2Cstripbooks-intl-ship%2C407\u0026amp;sr=1-1\"\u003eThe Phoenix Project\u003c/a\u003e เล่าเรื่องผ่านสายตาของ Bill Palmer - Manager ระดับกลางๆ ที่จับพลัดจับพลูถูกเลื่อนตำแหน่งขึ้นมาเป็น VP of IT Operations ใน Part Unlimited บริษัทขายชิ้นส่วนประกอบต่างๆ ของรถยนต์ที่กำลังเดิมพันกับ Phoenix Project ซอฟท์แวร์ตัวใหม่ที่จะช่วยกระตุ้นยอดขายและยกระดับบริการให้ล้ำหน้าคู่แข่งไปได้\u003c/p\u003e\n\u003cp\u003eผมพยายามจะสปอยเนื้อหาให้น้อยที่สุดแต่ผมบอกได้ว่า เนื้อเรื่องในหนังสือเล่มนี้มันเข้มข้นมากทุกๆ อย่างมันถาโถมมาอย่างหนักหน่วงและ \u003cstrong\u003eหลายๆ ครั้งมันตรงกับชีวิตจริง\u003c/strong\u003e (ถ้าคุณทำงานใน Software Industry มานานพอ) ทุกๆ หน้าที่เรามองผ่านสายตา Bill และพยายามแก้ปัญหาที่เข้ามามันเหมือนกับว่าเราได้ไปนั่งอยู่ตรงนั้น ในห้องประชุม NOC หรือแม้แต่ที่ Production Plant จริงๆ และหลายครั้งตัวผมเองก็คิดไม่ออกว่าจะแก้ปัญหาที่เข้ามาในเรื่องยังไง\u003c/p\u003e\n\u003cp\u003eแต่สิ่งที่ผมนับถือที่สุดกับ Bill เลยคือความที่ Bill เป็นคนที่ Humble และ Empowered มาก ซึ่งเราจะเห็นได้จากหลายๆ ครั้งที่เวลาเจอปัญหาแล้ว Bill คิดไม่ออกแต่ทีมช่วยกันคิดออก Bill จะเปลี่ยนโหมดเป็น supporter ไอเดียนั้นทันทีและหลายครั้งก็ช่วย Facilitate ให้ไอเดียนั้นต่อยอดขึ้นไปอีก ในขณะเดียวกันหลายครั้งเราก็จะเห็น Bill จมไปกับความคิด กับไอเดียที่เกิดขึ้นจากเหตุการณ์ต่างๆ ที่ผ่านมาแล้วเกิด Aha! Moment ขึ้นด้วย ซึ่งนอกจาก Bill มีอีก 2 ตัวละครที่ผมอยากพูดถึงคือ Erik (Board Candidate), Brent (Lead Engineer)\u003c/p\u003e","title":"[Book Review] The Phoenix Project เพราะ IT Operation ก็ไม่ต่างกับ Production Plant"},{"content":"ผมไม่รู้ว่าจะมีใครมาใช้ emacs แบบ เป็น text-editor ตัวแรกเลยมั้ย ผมไม่ใช่คนนึงแน่ๆ ซึ่งพอเราเปลี่ยนเครื่องมือ มันจะอารมณ์เดียวกับเราเปลี่ยนภาษา Programming ที่เราเขียนทุกวันเลย เพราะสิ่งแรกๆ ที่เราพยายามทำคือ \u0026ldquo;เราพยายามจะทำสิ่งเดียวกับที่เราเคยทำได้จากภาษาเก่า ในภาษาใหม่\u0026rdquo; ลองเปลี่ยนคำว่า ภาษา เป็น text-editor ดูครับ แล้วลองตอบตัวเองดูว่าเราอยากทำอะไรได้บ้าง\nคำตอบของคำถามข้างบนมันน่าจะเยอะมาก หรืออาจจะขอแค่มี syntax highlight ผมเชื่อว่าแต่ละคนมีคำตอบของตัวเอง ซึ่งผมก็มีคำตอบของผมด้วย และคิดว่าเป็นหัวข้อที่ดีที่จะเอามาเขียน EP2 ที่ค้างคาไว้มานาน หลังจากเกริ่นมานาน วันนี้ขอเสนอตอน \u0026ldquo;สภาพแวดล้อม\u0026rdquo; ครับ\n💬 ในบล็อกนี้ผมอาจจะมี Reference ถึง key Vim เยอะมาก ไม่ใช่เพราะมันไม่ดี แต่เพื่อต้องการให้เห็นภาพว่า Design philosophy มันต่างกัน และส่วนตัวผมยังชอบ Vim อยู่นะ :wq!\nเปิดประตูและปิดประตู มันจะมี Joke ที่คนใช้ Vim โดนล้อกันบ่อยๆ คือปิด Vim กันไม่เป็น ซึ่งส่วนตัวผมมองว่า Emacs ก็ไม่ต่างกัน ถึงมันจะมี Menu bar ให้ข้างบนก็เถอะ\nถ้าต้องการเปิดไฟล์ใน emacs เราจะเปิดจาก terminal เป็น emacs ก็ได้ แต่ถ้าเผลอเข้ามาใน emacs แล้วจะใช้ C-x C-f ครับ\n💬 วิธีกดปุ่มอย่างที่เห็นข้างบนตัว ctrl หรือที่ชอบเขียนใน Document เป็น C- ก็คือกด ctrl แช่ไว้แล้วตามด้วยตัวอักษรครับ แต่ถ้าเป็น combo แบบข้างบนกด ctrl ค้างไว้เลยแล้วกด x f ก็ได้ครับ\nทีนี้ก็มาถึง Highlight เรา เราจะปิด emacs ยังไงดี การปิด emacs จะใช้คีย์ C-x C-c ครับ ซึ่งถ้าเราไม่ได้แก้ไขอะไรใน buffer ที่เราเปิดมันก็จะปิดไปเลย แต่ถ้ามีมันก็จะถามว่าจะ Save มั้ย จะปิดจริงๆ ใช่มั้ยนะ\nเดินและกระโดด สิ่งแรกที่ผมโฟกัสเลยคือการเดิน ซึ่งเอาจริงๆ เราสามารถเลือกที่จะไม่รู้อันนี้ก็ได้ แล้วใช้แค่ Arrow key ที่มีติดมากับคีย์บอร์ดส่วนใหญ่ก็ได้ แต่เหตุผลแรกคีย์บอร์ดผมไม่ใช่คีย์บอร์ดเหมือนคนส่วนใหญ่และสองคือ พอเราเคยใช้ Vim มา เราจะรู้ได้ถึงประสิทธิภาพในการเดินที่ไม่ต้องขยับมือออกจาก Homerow อยู่แล้ว ซึ่งสองเหตุผลนี้คือเหตุผลที่ผมเลือกที่จะเรียนรู้การเดินแบบ emacs ครับ\nวิธีการเดินใน emacs จะใช้ Modifier key → Ctrl แล้วตามด้วยคีย์ที่เอาไว้ใช้เดิน ซึ่งประกอบด้วย\nC-f → Forward คือเลื่อน cursor ไปข้างหน้า C-b → Backward คือเลื่อน cursor ไปข้างหลัง C-p → Previous คือเลื่อน cursor ขึ้นบน C-n → Next คือเลื่อน cursor ลงล่าง ซึ่งสำหรับคนที่เปลี่ยน Keyboard layout อย่างผมมันจำง่ายกว่าคีย์ Vim ที่ intention เอาไว้มือขวา แต่ emacs เลือกที่จะแมพตามคำที่ระบุ Behavior มัน ซึ่งแปปเดียวก็จำได้เลย\nในส่วนของการกระโดดนั้น ถ้าเป็นการกระโดดข้ามคำ การเดินหน้ากับถอยหลังจะใช้คีย์เดียวกันเลยคือ f, b แต่เปลี่ยน Modifier คีย์เป็น M หรือ Meta key หรือ Alt หรือ Option key (1) แต่ถ้าเป็นการกระโดดไปที่ตัวสุดท้ายของบรรทัดหรือถอยไปต้นบรรทัดจะใช้ a, e แทน ซึ่งสรุปได้ตามนี้ครับ\nM-f → Forward Word M-b → Backward Word C-a → Beginning of Line C-e → End of Line ส่วนการกระโดดขึ้นลงนั้น จะเริ่มจำยากกว่าที่ไล่มาข้างบนคือ movement by balanced expression. ซึ่งจะใช้ { } ในการกระโดดระหว่าง Block ของ expression หรือ Paragraph ถ้าพูดแบบบ้านๆ แต่เราก็สามารถกระโดดขึ้นไปบรรทัดแรกหรือบรรทัดสุดท้ายของไฟล์ได้ด้วยตามนี้ครับ\nM-{ → Move to Beginning of Paragraph M-} → Move to End of Paragraph M-\u0026lt; → Move to Beginning of Buffer M-\u0026gt; → Move to End of Buffer อันที่จริง ยังมีอีกหลายคีย์ที่ช่วยให้เราเดินและกระโดดได้อีกในหลายรูปแบบ แต่ข้างบนเป็นรูปแบบที่ผมใช้บ่อยจนติดเป็น Muscle Memory ไปละ\n💬 แรงบันดาลใจหนึ่งที่ผมมาใช้ emacs เพราะตอนผมไปเรียน HtDP รุ่นพี่ผมเค้าบอกว่าเนี่ยคีย์ที่กดใน Racket เนี่ยมันคีย์เดียวกับ emacs เลย แล้วมันกดได้ในหลายโปรแกรมเลยนะ พอผมไปลองเท่านั้นแหละ จริง! แทบจะทุกโปรแกรมครับ\nBuffer ก่อนจะไปถึง Window ที่ผมเชื่อว่าหลายๆ คนชินมากับ Editor อื่นๆ เหมือนผม ผมอยากจะให้ทุกคนลองรู้จักกับระบบ Buffer ใน emacs ก่อน เพราะส่วนตัวผมชอบ emacs มากระดับที่เรียกได้ว่า Paradigm shift กันเลยทีเดียว\nเวลาเราเปิดไฟล์ขึ้นมาใน emacs ตัวไฟล์จะไม่โดนแก้ไขตรงๆ แต่แรกครับ แต่มันจะถูกโหลดมาเก็บไว้ใน buffer ของ emacs ซึ่งใน emacs มี buffer หลายแบบมากทั้ง\n*file* - ตัวนี้เราน่าจะยุ่งบ่อยสุดละ มันคือ buffer ที่เกิดจากเวลาเราเปิดไฟล์ขึ้นมาใน emacs ครับ ซึ่งปกติมันก็จะตั้งชื่อให้เป็นชื่อไฟล์ที่เราเปิดโดยอัตโนมัติ\n*scratch* - ตัวนี้เป็นเหมือนกระดาษทด เอาไว้ให้เราจดอะไรก็ได้\n*message* - ตัวนี้เป็นพวกแจ้งเตือนที่ emacs เตือนเรา อย่างเช่นตอนเราจะปิด emacs ตอนยังไม่เซฟไฟล์\n*help* - ตัวนี้ตามตัวครับเป็นคู่มือให้เราใช้ emacs\nทีนี้เวลาเราทำงานกับ buffer สำหรับผมคิดว่ามี 2 อย่างที่ควรรู้เอาไว้คือ การสลับ buffer เวลาเราเปิดหลายๆ ไฟล์ และการลบ buffer ที่ไม่ใช้แล้วออกไปครับ\nการสลับ buffer เราสามารถกด C-x b ได้ครับ จะเป็นการเปิดเมนูให้เราสลับ buffer ได้โดยพิมพ์ชื่อเอาก็ได้ หรือจะเลื่อนขึ้นลงก็ได้ครับ (ในภาพเป็นตัวที่ Modify ใน Doom แล้วแต่ตัวมาตรฐานก็กด tab เพื่อดู list ของ buffer ทั้งหมดได้ครับ\nอีกอย่างคือ พอเราเปิดไฟล์มาเยอะๆ ตัว buffer เราก็จะเริ่มล้นหรือทำให้หาไฟล์ที่ต้องการยากขึ้น ไม่ต่างจากเวลาเราเปิด chrome tab ไว้เยอะๆ เลย ซึ่งวิธีการลบ buffer คือกด C-x k ครับ ซึ่งจะเหมือนกับตอนเราปิด emacs คือถ้าเรายังไม่เซฟไฟล์มันจะถามก่อนว่าจะเซฟก่อนมั้ย\nBuffer ยังทำอะไรได้อีกเยอะมากครับ ทั้งเปิด email, feed, calendar หรือแม้กระทั่งเป็น terminal emulator แต่เอาไว้ตอนต่อๆ ไปผมค่อยไปเล่าถึงตรงนั้น แล้วก็ท้ายสุด ใน Vim ก็มี buffer นะ แต่ผมไม่เคยใช้เลย ฮาาา\nWindow ถ้าเป็นใน text-editor ตัวอื่นๆ แทบจะทั้งหมดหรืออย่างน้อยก็ที่ผมรู้จัก เค้าจะเรียกสิ่งนี้ว่า Pane ครับ ซึ่งสามารถ Split ได้ทั้ง Horizontal, Vertical เลยโดยคีย์หลักๆ ที่ผมใช้จะมี\nC-x 2 - อันนี้ไว้ Split Horizontal หรือแบ่งบนล่างครับ\nC-x 3 - อันนี้ไว้ Split Vertical หรือแบ่งซ้ายขวาครับ\nC-x o - อันนี้เป็นตัวอักษร O (Omongo) นะครับ เอาไว้สลับระหว่าง Window\nC-x 0 - อันนี้เป็นเลข 0 นะครับ เอาไว้ลบ window ที่กำลังโฟกัสอยู่ (Close this window)\nC-x 1 - อันนี้เอาไว้ปิดที่เหลือทั้งหมด (Close other window)\nซึ่งหลังจากใช้ได้ซักพักผมรู้สึกว่ามันคุ้นๆ นะ จนผมค้นพบว่าคีย์มันคล้าย tmux มากๆ เลยครับ อาจจะคล้ายแค่ C-x o พวก Split อะไรอาจจะไม่ตรง แต่มันทำให้ผมเข้าใจ concept switch window ได้เร็วมากๆ นอกจากนั้น ถ้าเราเปิด 3 Window ขึ้นไป ใน Doom emacs มันจะมีฟีเจอร์ highlight window ต่างๆ เป็นตัวอักษรครับ ถ้าอยากไปหน้าไหน ก็กดตัวอักษรที่มัน highlight แดงๆ เลยไม่ต้องกด C-x o ย้ำๆ หลายๆ ครั้งครับ\nFrame Frame ถ้าแปลตรงตัวคือกรอบใช่มั้ยครับ ใน emacs มันหมายถึงหน้าต่างทั้งหน้าเลย (ไม่ใช่หน้าต่าง Window ที่ผมพูดถึงข้างบนนะ) ซึ่งผมว่าสิ่งที่อธิบายได้ดีที่สุดคือมันเหมือน tmux window ที่เรากด C-b c มากๆ ครับ\nตัว Frame มีประโยชน์มากๆ เอาไว้ให้เราแยก Workspace ได้จะในกรณีที่เราเปิด Window เยอะๆ แล้ว ก็อยากเปิดอันอื่นด้วย แต่หน้าไม่พอ ส่วนตัวผมไม่ค่อยได้ใช้ฟีเจอร์นี้เท่าไร แทบจะนับครั้งได้ เลยไม่รู้จะเล่าอะไรเท่าไร\nTab พอผ่านมาทั้ง Buffer, Windows, Frame หลายคนน่าจะสงสัยว่า อ่าวแล้ว Tab ละในพวก text-editor อื่นๆ ก็มีนิ ใช่ครับ emacs ก็มีแต่ผมไม่เคยใช้ครับ ผมใช้แค่ข้างบนก็พอละ\nแต่ถ้ามามองอีกมุมนึงผมว่า concept ของ buffer มันทดแทน tab ได้เลยนะ เพราะถ้าอยากไปดูไฟล์ไหนก็เปิด buffer ขึ้นมาดูเอา อีกเหตุผลนึงคือผมว่ามันโฟกัสกว่าด้วย ไม่ต้องเห็น tab ให้รกหูรกตา\nEmacs Pinky ถ้าใครเพิ่งมาลอง emacs ใหม่ๆ แล้วมาถึงจุดนี้ ขอแสดงความยินดีด้วยครับ คุณได้สัมผัสกับสิ่งที่ชาว emacs โดนล้อมาหลายปีนั่นก็คือ Emacs Pinky ครับ ถ้าสังเกตุ เราใช้นิ้วก้อยกด Ctrl (C) กันซ้ำๆ เยอะมากและถ้าใช้บ่อยๆ หนักๆ มันก็เกิดอาการบาดเจ็บได้ ซึ่งเอาจริงๆ มันก็ไม่ค่อยดีกับสุขภาพนิ้วเท่าไร วิธีการบรรเทาขั้นแรก แต่ก็ยังเจ็บนิ้วก้อยอยู่ คือย้าย ctrl มาไว้ที่ปุ่ม Caplock เอาครับ อารมณ์เดียวกับชาว Vim ที่ย้าย ESC มาอยู่ที่ Caplock เหมือนกัน\nถ้าใครย้ายแล้วยังรู้สึกปวดนิ้วก้อยอยู่ ผมก็แนะนำคีย์บอร์ดที่ช่วยเพิ่มการใช้งานนิ้วโป้ง อย่างมีนัยยะสำคัญอย่าง Ergodox EZ หรือ Kinesis Advantage2 ก็ได้ครับ จะช่วยให้เราย้ายปุ่มพวก Modifier key ให้มาอยู่ที่นิ้วโป้งเราได้ ช่วยลดภาระของนิ้วก้อยไปได้มากๆ\nแต่ส่วนตัวผมถึงจะใช้ Ergodox EZ แต่ผมก็ยังแมพไว้ที่นิ้วก้อยอยู่ครับ เพราะ Thumb cluster ผมมันแมพปุ่มอื่นจนเต็มแล้ว T_T\nก็ประมาณนี้ครับตอนสอง ผมว่าวิธีการที่ emacs เค้าออกแบบสภาพแวดล้อมขึ้นมานี่น่าสนใจมากเป็นอีก Philosophy ที่ก็มีจุดแข็งในตัวมันเองครับ ถ้าใครชอบซีรีย์นี้ก็กดติดตามได้ใน Hashnode ครับ พอถึงเวลาที่ผมออกตอนใหม่เดี๋ยวมันก็แจ้งเตือนเอง แล้วเจอกันใหม่ตอนหน้าครับ\nReference https://www.masteringemacs.org/article/effective-editing-movement https://www.oreilly.com/library/view/learning-gnu-emacs/0596006489/ch04.html https://en.wikipedia.org/wiki/Emacs#Emacs_pinky Footnote (1) อันนี้แล้วแต่ emacs variations ที่ลงในเครื่องเลยครับส่วนตัวผมใช้ Homebrew-emacsmacport ทำให้มันแมพกับ Option แทนที่จะแมพกับ Cmd เหมือนกับบาง Variations\n","permalink":"https://yothinix-com.pages.dev/emacs-env/","summary":"\u003cp\u003eผมไม่รู้ว่าจะมีใครมาใช้ emacs แบบ เป็น text-editor ตัวแรกเลยมั้ย ผมไม่ใช่คนนึงแน่ๆ ซึ่งพอเราเปลี่ยนเครื่องมือ มันจะอารมณ์เดียวกับเราเปลี่ยนภาษา Programming ที่เราเขียนทุกวันเลย เพราะสิ่งแรกๆ ที่เราพยายามทำคือ \u0026ldquo;เราพยายามจะทำสิ่งเดียวกับที่เราเคยทำได้จากภาษาเก่า ในภาษาใหม่\u0026rdquo; ลองเปลี่ยนคำว่า ภาษา เป็น text-editor ดูครับ แล้วลองตอบตัวเองดูว่าเราอยากทำอะไรได้บ้าง\u003c/p\u003e\n\u003cp\u003eคำตอบของคำถามข้างบนมันน่าจะเยอะมาก หรืออาจจะขอแค่มี syntax highlight ผมเชื่อว่าแต่ละคนมีคำตอบของตัวเอง ซึ่งผมก็มีคำตอบของผมด้วย และคิดว่าเป็นหัวข้อที่ดีที่จะเอามาเขียน EP2 ที่ค้างคาไว้มานาน หลังจากเกริ่นมานาน วันนี้ขอเสนอตอน \u0026ldquo;สภาพแวดล้อม\u0026rdquo; ครับ\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e💬 ในบล็อกนี้ผมอาจจะมี Reference ถึง key Vim เยอะมาก ไม่ใช่เพราะมันไม่ดี แต่เพื่อต้องการให้เห็นภาพว่า Design philosophy มันต่างกัน และส่วนตัวผมยังชอบ Vim อยู่นะ :wq!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"เปดประตและปดประต\"\u003e\u003cstrong\u003eเปิดประตูและปิดประตู\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eมันจะมี Joke ที่คนใช้ Vim โดนล้อกันบ่อยๆ คือปิด Vim กันไม่เป็น ซึ่งส่วนตัวผมมองว่า Emacs ก็ไม่ต่างกัน ถึงมันจะมี Menu bar ให้ข้างบนก็เถอะ\u003c/p\u003e\n\u003cp\u003eถ้าต้องการเปิดไฟล์ใน emacs เราจะเปิดจาก terminal เป็น emacs ก็ได้ แต่ถ้าเผลอเข้ามาใน emacs แล้วจะใช้ \u003ccode\u003eC-x C-f\u003c/code\u003e ครับ\u003c/p\u003e","title":"Emacs diary EP2: สภาพแวดล้อม"},{"content":"ลืมหัวข้อ blog นี้ไปก่อนนะครับ แล้วลองพยายามเดาดูว่าโค้ด Java ข้างล่างนี้พยายามทำอะไร มันก็ดูตรงไปตรงมาใช่มั้ยครับ แล้วถ้ารันออกมาสมมติวันนี้วันที่ 1 ธันวาคม 2021 สิ่งที่ function นี้คืนกลับมาก็\nเป็น 2020-12-01 ใช่มั้ยครับ ถ้าเราเขียน Unit test ไว้ เทสนี้ก็น่าจะผ่านได้ง่ายๆ ปกติไม่มีอะไร\nเรื่องมันมีอยู่ว่า ถ้าสมมติวันนี้เป็นวันที่ 31 ธันวาคม 2021 แล้วโค้ดชุดนี้เอาไว้บอกว่าควรจะจ่ายเงินเดือนเราตอนวันที่เท่าไร ลองทายดูมั้ยครับว่าจะเกิดอะไรขึ้น\nรู้จักกับ DateTimeFormatter กันก่อน ผมสังเกตุเห็น อย่างน้อยก็ใน Codebase ที่ผมทำงานด้วยอยู่ว่า Java Developer ส่วนใหญ่จะยังคุ้นเคยกับ Date API ที่มีมาตั้งแต่ Java 1.0 หน้าตาประมาณโค้ดข้างล่างครับ\nซึ่ง จะเห็นได้ว่า Date API ตัวเก่าของ Java นั้นมีปัญหาเยอะมาก อย่างเช่นการที่จะปั้นเวลาซักอย่างก็เริ่มที่ปี 1900 แล้วบวกไปเอาหรือเดือนที่เริ่มที่ index ที่ 0 ซึ่งไม่ใช่ว่าทางทีมพัฒนา Java จะไม่พยายามแก้ปัญหานี้นะครับ ความพยายามแรกคือ Calendar class ที่ออกมาใน Java 1.1 แต่ก็ยังมีปัญหาหลายๆ อย่างอยู่ จน Java Developer หลายคนเลือกที่จะไปใช้ 3rd Party Library อย่าง Joda-Time แทน ซึ่งหลังจาก Oracle ได้ยึด Java ไปก็เลยเกิด Date/Time API ตัวใหม่ขึ้นมาใน Java 8 ซึ่งมีพื้นฐานหลายๆ อย่างมาจาก Joda-Time ครับ\nซึ่งใน API ตัวใหม่นอกจาก LocalDate, LocalTime ฯลฯ ตัว API ยังมาพร้อมกับ Formatter กับ Parser ตัวใหม่ด้วยครับชื่อว่า DateTimeFormatter ซึ่งช่วยให้เรา Parse เวลาเข้ามาได้ง่ายขึ้นพร้อมกับ constants อีกจำนวนนึงที่ช่วยให้เราประหยัดเวลาในการปั้น Date format ไปได้เยอะเลย แถมยัง Thread-safe ด้วยนะ\nPattern letters and Symbols for Formatting and Parsing เวลาที่เรา Format Date/Time เนี่ย pattern ส่วนใหญ่ที่เราต้องทำคงหนีไม่พ้น yyyy-MM-dd ดูเผินๆ มันก็ตรงตัวใช่มั้ยครับ อาจจะมีแค่ M เดือน (Month-of-year) ที่ต้องเปลี่ยนไปใช้ M ใหญ่ เพราะมันดันไปพ้องกับอีก m นึงในหน่วยเวลาคือ นาที (minute-of-hour)\nซึ่งพวกเราน่าจะคุ้นเคยกับ pattern พวกนี้ดีอยู่แล้วใช่มั้ยครับ แล้วผมจะเขียนบล็อกนี้มาทำไมนะ ผมถามอีกทีว่า พวกเราน่าจะคุ้นเคยกับ pattern พวกนี้ดีอยู่แล้วใช่มั้ยครับ?\nพอดีวันนี้ ในขณะที่ผมไต่ไปตาม codebase ที่ผมดูแลอยู่ผมไปสะดุดกับ pattern หน้าตาแบบภาพบนสุดเลยครับคือ YYYY-MM-dd ซึ่ง ถ้ามองผ่านๆ ผมก็อาจจะไม่คิดอะไร แต่ผมดันไปเอะใจว่า ผมเคยเห็นแต่ yyyy-MM-dd นี่นา แล้ว YYYY กับ yyyy มันต่างกันยังไงนะ\nเรื่องของปี (ต่างๆ) ถ้าเทียบจากตาราง Pattern Letters and Symbols ในหัวข้อที่แล้ว เราจะเจอว่า y เนี่ยมันคือ year-of-era ส่วน Y มันเป็น week-based-year ซึ่งในส่วนของ Presentation ก็มีความหมายว่า year เหมือนกัน และถ้ามองดูดีๆ จะเห็นว่าเรามี u ด้วยซึ่งมีความหมายว่า year เหมือนกัน\nส่วนที่ยิ่งประหลาดไปอีกคือ Example ครับ จะเห็นว่า u กับ y เนี่ยเหมือนกันเลยคือ 2004; 04 แต่ว่า Y เนี่ยดันเป็น 1996; 96 อะไรของ Java วะคับ อะไรคือ year-of-era อะไรคือ week-based-year แล้วมันต่างจากปีที่เรารู้จักกันยังไง ผมจะสรุปสั้นๆ ให้ฟัง\nYear-of-era (y เล็ก หรือ u) ตัวเนี่ยไม่มีอะไรซับซ้อนเลยครับ มันคือปีอย่างที่เรารู้จักกันนี่แหละ หรือถ้าทางเทคนิคหน่อยคือปีในทาง Gregorian calendar ที่เราใช้กันอยู่เป็นปกติหรือ ค.ศ. นั่นเองครับ ถ้าเทียบกับปีปัจจุบันคือ 2021\nWeek-based-year (Y ใหญ่) ตัวนี้แหละที่เป็นสาเหตุให้ผมต้องเขียนบล็อกนี้ขึ้นมา Week-based-year คือการนับปีตามสัปดาห์ครับ ซึ่งเราก็น่าจะเอะต่อว่า แล้วสัปดาห์นี่มันเริ่มนับยังไงนะ บางปฏิทินก็นับวันอาทิตย์ บางก็นับวันจันทร์ ในส่วนของ Java นี้นับปฏิทินเริ่มที่วันจันทร์ครับตามมาตรฐาน ISO 8601\nถ้ายังงงอยู่ งั้นลองดูตัวอย่างนี้นะครับ (จริงๆ App Calendar ของ Apple นี่มันก็แอบสปอยอยู่นะ) ถ้าเราใช้ YYYY (Week-based-year) ตอนเรา Format date ในวันที่ 31 ธันวาคม 2021 แทนที่มันจะออกมาเป็น 2021-12-31 สิ่งที่คืนกลับมาจาก DateFormatter จะกลายเป็น 2022-12-31 ครับ เพราะว่าในสัปดาห์นี้ตั้งแต่วันจันทร์ที่ 27 ธันวาคม 2021\nแต่ละสัปดาห์เริ่มนับวันจันทร์จริงเหรอ? พอยิ่งขุดลึกลงไปอีก ผมเลยเจอว่าการที่จะนับแต่ละสัปดาห์จะเริ่มวันจันทร์หรือวันอาทิตย์ ขึ้นอยู่กับ Locale ที่เราใช้ในการ Format ครับโดยเราสามารถใส่หรือไม่ใส่ก็ได้เป็น arguments ตัวที่สองของ DateTimeFormatter.ofPattern() ซึ่ง default Locale จะเป็น Locale.US ซึ่งนับวันอาทิตย์เป็นวันเริ่มต้นของสัปดาห์ครับ ทำให้ในเคสข้างบนของเรามันจะนับ YYYY เป็นปี 2022 ตั้งแต่วันอาทิตย์ที่ 26 ธันวาคม 2021 เลย\nแต่ถ้าเราอยากให้นับสัปดาห์เริ่มที่วันจันทร์เราสามารถเปลี่ยนไปใช้ Locale อื่นได้ครับ อย่างเช่น Locale.FRANCE จะเริ่มในวันจันทรแทน ซึ่งจะทำให้เคสวันอาทิตย์ที่ 26 ธันวาคม 2021 ยังคงเป็นปี 2021 อยู่ครับ\nแล้วเราควรจะใช้ตัวไหนดี u, y, Y ถ้าตอบแบบ Consult คงต้องตอบว่า It’s depends แต่ว่าผมสรุปให้คร่าวๆ ครับ\nu (year) ผมเข้าใจว่าในทาง Meaning ตัวนี้น่าจะเหมาะกับเราที่สุดครับ เพราะมันเป็นปีตรงๆ โดยไม่มีอะไร Constraint เลย แต่ผมเข้าใจที่หลายคนไม่เลือกใช้ เพราะมันน่าจะงงๆ เวลาไปเขียนร่วมกับหน่วยอื่นๆ คนเลยนิยม y มากกว่า\ny (year-of-era) ตัวนี้คนน่าจะใช้เยอะสุด แล้วน่าจะสับสนน้อยสุด เพราะเราชินกับมันมาจากหลายๆ ภาษา และโดยตัวมันเองก็สื่อออกมาด้วย แต่ตามที่มัน Design มามันถูกออกแบบให้ใช้คู่กับตัว G (era) ด้วยครับ แต่ถ้าเราไม่ใช้ผมว่าก็ไม่ผิดอะไรนะ ส่วนตัวผม Prefer ตัวนี้นะ\nY (week-based-year) ตัวนี้เหมาะกับ calculation อะไรก็ตามที่เราต้องทำเป็น week-based ครับ ซึ่งอาจจะใช้กับงานที่เป็น batch รันรายสัปดาห์แล้วเก็บแค่ปีกับสัปดาห์\nก็ประมาณนี้ครับ คิดว่าใครที่อ่านมาถึงตรงนี้น่าจะได้อะไรติดไม้ติดมือกลับไปบ้าง ผมกำลังสงสัยว่าภาษาอื่นๆ น่าจะมีเรื่องนี้เหมือนกัน ซึ่งต้องบอกว่า เวลา เนี่ยเป็นหนึ่งในเรื่องที่ยากของ Computer เลยครับและถ้าเราไม่ระวัง เราจะเจอบั๊กแปลกๆ ที่ชอบมาในเวลาแปลกๆ อย่างสิ้นปีได้ ถ้าชอบบล็อกแนวนี้ก็ฝากกดไลค์ กดแชร์ หรือคอมเมนต์ด้วยนะครับ แล้วเจอกันใหม่บล็อกหน้าครับ\nReference Chapter 12 - manning.com/books/modern-java-in-action baeldung.com/java-datetimeformatter stackoverflow.com/questions/26431882/differ.. stackoverflow.com/questions/41177442/uuuu-v.. ","permalink":"https://yothinix-com.pages.dev/java-year-behavior/","summary":"\u003cp\u003eลืมหัวข้อ blog นี้ไปก่อนนะครับ แล้วลองพยายามเดาดูว่าโค้ด Java ข้างล่างนี้พยายามทำอะไร มันก็ดูตรงไปตรงมาใช่มั้ยครับ แล้วถ้ารันออกมาสมมติวันนี้วันที่ 1 ธันวาคม 2021 สิ่งที่ function นี้คืนกลับมาก็\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/java-year-behavior/lfVaJ8HNV_hu_bc77c8395af92cfa.webp\"\n       srcset=\"/java-year-behavior/lfVaJ8HNV_hu_7408599a6dfa8fa0.webp 480w, /java-year-behavior/lfVaJ8HNV_hu_bb8a658fc8c5b508.webp 960w, /java-year-behavior/lfVaJ8HNV_hu_bc77c8395af92cfa.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"810\"\n       alt=\"SomeUtils_java.png\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eเป็น 2020-12-01 ใช่มั้ยครับ ถ้าเราเขียน Unit test ไว้ เทสนี้ก็น่าจะผ่านได้ง่ายๆ ปกติไม่มีอะไร\u003c/p\u003e\n\u003cp\u003eเรื่องมันมีอยู่ว่า ถ้าสมมติวันนี้เป็นวันที่ 31 ธันวาคม 2021 แล้วโค้ดชุดนี้เอาไว้บอกว่าควรจะจ่ายเงินเดือนเราตอนวันที่เท่าไร ลองทายดูมั้ยครับว่าจะเกิดอะไรขึ้น\u003c/p\u003e\n\u003ch2 id=\"รจกกบ-datetimeformatter-กนกอน\"\u003e\u003cstrong\u003eรู้จักกับ DateTimeFormatter กันก่อน\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eผมสังเกตุเห็น อย่างน้อยก็ใน Codebase ที่ผมทำงานด้วยอยู่ว่า Java Developer ส่วนใหญ่จะยังคุ้นเคยกับ Date API ที่มีมาตั้งแต่ Java 1.0 หน้าตาประมาณโค้ดข้างล่างครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/java-year-behavior/kL7ArNt8K_hu_3c4e19a5eda88d50.webp\"\n       srcset=\"/java-year-behavior/kL7ArNt8K_hu_3224114059aece06.webp 480w, /java-year-behavior/kL7ArNt8K_hu_63b5540bf5387b80.webp 960w, /java-year-behavior/kL7ArNt8K_hu_3c4e19a5eda88d50.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"810\"\n       alt=\"SomeOldUtils_java.png\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eซึ่ง จะเห็นได้ว่า Date API ตัวเก่าของ Java นั้นมีปัญหาเยอะมาก อย่างเช่นการที่จะปั้นเวลาซักอย่างก็เริ่มที่ปี 1900 แล้วบวกไปเอาหรือเดือนที่เริ่มที่ index ที่ 0 ซึ่งไม่ใช่ว่าทางทีมพัฒนา Java จะไม่พยายามแก้ปัญหานี้นะครับ ความพยายามแรกคือ Calendar class ที่ออกมาใน Java 1.1 แต่ก็ยังมีปัญหาหลายๆ อย่างอยู่ จน Java Developer หลายคนเลือกที่จะไปใช้ 3rd Party Library อย่าง Joda-Time แทน ซึ่งหลังจาก Oracle ได้ยึด Java ไปก็เลยเกิด Date/Time API ตัวใหม่ขึ้นมาใน Java 8 ซึ่งมีพื้นฐานหลายๆ อย่างมาจาก Joda-Time ครับ\u003c/p\u003e","title":"เรื่องประหลาดๆ ของการนับปีใน Java"},{"content":"เคยมีความรู้สึกแบบนี้มั้ยครับ อารมณ์ประมาณว่า อยากจะเรียนคอร์สนั้นที่ซื้อไว้ตั้งนานแล้วให้จบ อยากจะอ่านหนังสือเล่มที่ซื้อเมื่อเดือนก่อน อยากจะทำ side project ที่คิดไว้ให้ออกมาเป็นรูปเป็นร่าง อยากจะมีทำให้ความสัมพันธ์ในชีวิตกับคนที่เราแคร์ดีขึ้น อะไรแบบนี้ แต่รู้ตัวอีกทีก็หมดวันละ และพอมองไปรอบๆ ตัวก็จะเห็นอนุเสาวรีย์ของความสิ้นหวังวางอยู่ ซึ่งหลายๆ ครั้งทุกปัญหามันจะกลับมาที่สิ่งเดียวคือ เราอยากมีเวลามากกว่านี้เหลือเกิน\nถ้าคุณมีความรู้สึกแบบนี้ ยินดีด้วยคุณไม่ได้เป็นอยู่คนเดียว ผมก็เป็นและอีกหลายๆ คนก็เป็นครับ ซึ่งความรู้สึกแบบนี้ ส่วนตัวผมเองก็ปล่อยมันไว้นานมาก แต่ก็รู้สึกว่าตัวเองยุ่งมากทั้งงานหลวง งานเสริม งานเพื่อสังคม มันอยู่ในทุกช่วงเวลาของชีวิตตั้งแต่ตื่นนอน จนนอนหลับ เรื่อยไปจนเสาร์ อาทิตย์ จนแทบไม่เคยได้อยู่กับตัวเอง\nผมเป็นอย่างนั้นมาตลอด หลายเดือนมากจนกระทั่งช่วงต้นเดือนพฤศจิกายนที่ผ่านมาผมป่วย ซึ่งตอนแรกเหมือนจะหายเร็ว เอาไปเอามากินเวลาไป 2 สัปดาห์เต็มๆ กว่าจะดีขึ้น ซึ่ง 2 สัปดาห์ที่นอนป่วย ที่ต้องพักผ่อน ให้ยาผ่านสายน้ำเกลือ เป็นครั้งแรกในรอบหลายเดือนเลยที่ผมได้หยุดจริงๆ คำว่าหยุดผมหมายถึงทุกอย่างที่ผมบอกว่าผมยุ่งมาก ทั้งงานหลวง งานเสริม งานเพื่อสังคม ทุกอย่างหยุดหมด\nในช่วงเวลานั้นแรกๆ สิ่งที่ผมทำนอกจาก กินกับนอน คือไถมือถือไปเรื่อยๆ ไถจนแอพมันล็อกแล้วแจ้งเตือนว่า Digital balance วันนี้หมดแล้วนะ ช่วงแรกๆ ผมก็กด ignore มันไปแล้วก็ไถๆ ต่อจนนอน วนอยู่อย่างนี้หลายวัน จนวันนึงเหมือนผมก็ตั้งคำถามกับตัวเองว่า ทำอะไรอยู่วะ แล้วผมซึ่งหยิบ Kindle มาด้วยพอดีก็เปิดหนังสือ Make Time ขึ้นมาอ่านอีกครั้ง หลังจากที่เคยอ่านเมื่อหลายปีมาแล้ว แล้วผมค้นพบว่า มันกลับมาหาผมได้ถูกช่วงเวลาชีวิตมาก\nMake Time เป็นเรื่องของการหาเวลาเพื่อให้เราได้ทำในสิ่งที่เราอยากทำครับ ไอเดียของหนังสือเล่มนี้มันง่ายแบบนี้เลย ซึ่งแบ่งเป็น 3 ขั้นตอนหลัก และ 1 ขั้นตอนเสริม\nHighlight - อย่างแรกเลยคือ เราต้องหาว่า เราอยากทำอะไร ซึ่งมันเป็นอะไรก็ได้ที่เราอยากทำ แต่รู้สึกว่าไม่มีเวลาที่จะทำมันซักที Laser - อย่างที่สองคือ เลเซอร์หรือโฟกัส จะเป็นเทคนิคที่ช่วงให้เราได้ทำสิ่งที่เราอยากทำจริงๆ ไม่วอกแวกไปไหน Reflect - อย่างที่สามคือ การย้อนกลับมาทบทวนในแต่ละวันว่า วันนี้เราได้ทำสิ่งที่เราอยากทำไปรึยัง รู้สึกยังไงบ้าง ลองเทคนิคอะไรไปบ้าง พรุ่งนี้อยากลองอะไร นอกจากนั้นยังมีอีก 1 ขั้นตอนเสริมเรียกว่า Energize หรือการเพิ่มพลังในการโฟกัส เพื่อที่เราจะได้มีพลังงานความพร้อมเหลือพอที่จะทำในสิ่งที่เราอยากจะทำและมีพลังเหลือเพื่อวันต่อๆ ไป\nซึ่งในแต่ละขั้นตอนจะมีเทคนิคเยอะมากรวมๆ แล้วเกือบๆ 90 เทคนิค ซึ่งยังไม่รวมเทคนิคเสริมในเว็บไซต์ที่อัพเดทเพิ่มมาเรื่อยๆ อีกด้วย ซึ่งต้องบอกก่อน (และในหนังสือก็บอกเหมือนกัน) ว่าไม่ใช่ทุกเทคนิคที่จะใช้ได้กับทุกๆ คน เราต้องลองด้วยตัวเอง แล้วลอง Reflect ดูว่า อันนี้มันเวิร์คกับเรามั้ยนะ แล้วก็อย่าไปซีเรียสกับมันมาก มันไม่ใช่ข้อสอบถ้าไม่เวิร์คก็แค่ลองใหม่ หรือไปลองเทคนิคอื่น ข้างล่างนี้คือบางส่วนของเทคนิคที่ผมลองแล้วเวิร์คสำหรับผมครับ\n1. Write It Down - อันนี้ตรงๆ ตัวเลยครับ เป็นการที่เราเขียนสิ่งที่เราอยากจะทำในวันนั้นใส่ลงในโพสอิท เป็นการประกาศว่า เห้ยเราจะทำสิ่งนี้นะวันนี้ ไม่มีอะไรจะห้ามเราได้ ซึ่งข้อดีของการเขียนลงโพสอิท แล้วแปะไว้ใต้จอคอมพิวเตอร์ คือมันจะคอยเตือนเราว่า อย่าลืมทำนะ อย่าลืมทำนะ อย่าลืมทำนะ อยู่ทั้งวันครับ\n17. Try a Distraction Free Phone - ส่วนตัวผมเป็นคนติดมือถือมาก อย่างที่ผมเล่าไว้ข้างบน ผมสามารถไถหน้าจอ Facebook, Twitter หรือในหนังสือเรียกว่า Infinity Pool ได้ทั้งวัน ซึ่งวันที่ผมตัดสินใจลองเทคนิคนี้แรกๆ ผมแค่ไม่หยิบมันขึ้นมา (22. Leave Devices Behind) พอรู้สึกว่า เออมันก็ทำได้นี่หว่า ผมก็เลยตัดสินใจลบแอพ Email ก่อนเลยอย่างแรก (24. Block Distraction Kryptonite) เรื่อยไปถึง Social Network แล้วผมก็จัดการเคลียร์หน้าจอ (20. Clear your homescreen) ที่ตอนแรกมีแอพที่ผมใช้บ่อยๆ ทุกอย่างออกให้หมดเหลือแต่ โทรศัพท์ กับ Messaging นอกจากนั้นผมไปที่ setting ของมือถือแล้วปิดแจ้งเตือนเกือบทุกแอพ (19.Nix Notifications) ออกหมดเลยเหลือไว้แค่ที่จำเป็น\n23. Skip the Morning Check-In - ผมว่าหลายคนเป็นรวมถึงผมเองด้วยที่ทุกเช้า สิ่งแรกที่เราทำหลังจากตื่นมาคือ การหยิบมือถือขึ้นมาเช็คว่ามีแจ้งเตือนอะไรบ้างระหว่างที่เรานอนหลับ ข้อนี้คือตรงกันข้ามกันคือ ตอนเช้าแทนที่จะหยิบมือถือมาเช็ค ก็ไปทำอาหารบ้าง อาบน้ำเร็วขึ้นบ้าง หรือบางครั้งก็แค่มองออกไปนอกหน้าต่างเฉยๆ และดื่มด่ำกับช่วงเวลาที่ในหัวเรายังไม่มีเรื่องอะไรต้องคิด ซึ่งการเปลี่ยนข้อนี้ผมทำร่วมกับ (83. Make your Bedroom a Bed room) ซึ่งไม่เอา Device อะไรเข้าไปในห้องนอนเลย อาจจะยกเว้น Kindle ไว้แต่ก็ห้ามเปิดแสง backlight ของจอด้วย\nก่อนที่จะไปต่อ ผมอยากบอกว่า 2 ข้อข้างบนนี่แหละ ที่เปลี่ยนชีวิตผมไปเลย มันทำให้ผมเจอสิ่งที่ตามหามานานมากๆ ในโลกที่เราแทบจะ Connect หากันตลอดเวลา สิ่งนั้นเรียกว่า ความสงบ ครับ เราไม่จำเป็นต้องรู้ตลอดก็ได้ว่าโลกเกิดอะไรขึ้นบ้าง หรือถ้าเกิดความสงสัยขึ้นมาผมถามกับตัวเองดังๆ ทุกครั้งว่า ถ้าเรารู้ตอนนี้มันจะต่างกับเรารู้พรุ่งนี้มั้ย? ซึ่งหลายๆ ครั้ง คำตอบมันคือ ไม่ต่าง\n26. Put Your Toys Away - ข้อนี้มันง่ายมากๆ และผมประหลาดใจกับผลลัพธ์มาก มันคือการที่เราปิด Bookmark toolbar ใน Browser ของเราไปครับ ซึ่งผมเชื่อว่าหลายๆ คนรวมถึงตัวผมเองด้วย bookmark toolbar จะเต็มไปด้วยเว็บที่เราเข้าบ่อยๆ อยู่แค่ปลายนิ้วคลิก นอกจากนั้นเรายังต้องเปลี่ยนหน้า New Tab ของ Browser แทนที่จะแสดงเว็บที่เราเข้าบ่อยสุด ให้แสดงภาพ Wallpaper เกลี้ยงๆ หรืออาจจะมีเวลาบอก แค่นั้นเลยครับ แล้วผมค้นพบว่า มันเพิ่มความสงบในการใช้คอมพิวเตอร์ขึ้นอย่างมีนัยยะสำคัญเลย เพราะเราไม่มีสิ่งที่เตือนเราถึงสิ่งต่างๆ อยู่ในสายตาเลยครับ\n55. Make a “Random Question” List - เคยมั้ยครับที่เวลาเราโฟกัสอะไรซักอย่างอยู่ มันจะมีไอเดียแว็บขึ้นมาในหัวที่บางครั้งมันก็อาจจะเกี่ยว หรือไม่เกี่ยวกับสิ่งที่เราทำตรงหน้าเลย เทคนิคนี้คือการที่เราแค่ถ้าเกิดไอเดียแว็บขึ้นมา ให้จดมันลงไปบนกระดาษครับ แล้วก็กลับมาโฟกัสกับสิ่งที่เราทำตรงหน้าต่อ\nจริงๆ ต้องบอกว่า มีอีกหลายเทคนิคมากครับ แต่แค่นี้คือที่คิดมาเร็วๆ แล้วมีผลกับตัวเองมากจริงๆ ซึ่งในส่วนของการ Reflect นั้น ด้วยความที่ขั้นตอนมันง่ายมาก มันเลยมาแทนที่ Journal ที่ผมทำแต่ก่อนไปได้เลย ซึ่งของพวกนี้ทำใน Notion ง่ายมากแค่สร้างตารางแล้วก็แค่มาทำมันทุกวัน\nผมเริ่มใช้เทคนิคนี้ได้ประมาณ 2 อาทิตย์กว่าๆ เองครับ รวมเวลาที่ป่วยด้วย แต่ยอมรับว่า ความต่างมันเยอะมาก อย่างแรกเลยคือ ผมแทบไม่ค่อยหยิบโทรศัพท์ขึ้นมาเล่นเวลาเบื่อๆ เลย เพราะมันไม่มีอะไรให้เล่นในนั้น หรืออย่างเวลากินข้าว ที่แต่ก่อนผมก็หยิบโทรศัพท์เล่นไปด้วย ก็เริ่มจะคุยกันคนข้างตัวมากขึ้น ทำให้ความสัมพันธ์มันดีขึ้นด้วย ไม่ต้องเจอแฟนบ่นว่าติด Social Network มากหรือใจลอยไม่ค่อยได้ยินแฟนพูดแบบแต่ก่อน นอกจากนั้นผมเริ่มอ่านหนังสือได้เยอะขึ้นมากๆ อย่างน้อยตอนนี้อ่านจบไปเล่มนึงแล้วคือ Make Time ในเวลาไม่กี่วัน และได้เริ่มอ่านอีกหลายเล่มพร้อมๆ กันในช่วงนี้ ฯลฯ มีอีกหลายอย่างมากที่อยู่ดีๆ ก็มีเวลาทำขึ้นมา ทั้งที่จริงๆ ผมก็มี 24 ชม. ไม่ต่างจากก่อนหน้านี้\nเอาเป็นว่า ถ้าใครรู้สึกว่ายุ่งๆ ควบคุมชีวิตตัวเองไม่ค่อยได้ ไหลไปตามความต้องการของคนอื่น รู้สึกว่าไม่ค่อยได้ทำอะไรที่อยากทำ ผมแนะนำเล่มนี้เลยครับ สำหรับผมมันช่วยมากและพาให้ผมมารู้จัก ความสงบ ในโลกนี้อีกครั้ง นอกจากนั้นยังมีแปลไทยด้วยในชื่อ ยุ่งจริง! หรือแค่คิดไปเอง ก็ลองไปหามาอ่านกันได้ครับ แล้วจริงๆ มีอีกเล่มที่อยากแนะนำคือ It Doesn’t Have To Be Crazy At Work อีกเล่ม แต่อ่านค้างไว้หลายเดือนแล้วยังไม่จบ ถ้าอ่านจบอาจจะได้มารีวิวให้อ่านกันอีกครั้งครับ\n","permalink":"https://yothinix-com.pages.dev/make-time/","summary":"\u003cp\u003eเคยมีความรู้สึกแบบนี้มั้ยครับ อารมณ์ประมาณว่า อยากจะเรียนคอร์สนั้นที่ซื้อไว้ตั้งนานแล้วให้จบ อยากจะอ่านหนังสือเล่มที่ซื้อเมื่อเดือนก่อน อยากจะทำ side project ที่คิดไว้ให้ออกมาเป็นรูปเป็นร่าง อยากจะมีทำให้ความสัมพันธ์ในชีวิตกับคนที่เราแคร์ดีขึ้น อะไรแบบนี้ แต่รู้ตัวอีกทีก็หมดวันละ และพอมองไปรอบๆ ตัวก็จะเห็นอนุเสาวรีย์ของความสิ้นหวังวางอยู่ ซึ่งหลายๆ ครั้งทุกปัญหามันจะกลับมาที่สิ่งเดียวคือ เราอยากมีเวลามากกว่านี้เหลือเกิน\u003c/p\u003e\n\u003cp\u003eถ้าคุณมีความรู้สึกแบบนี้ ยินดีด้วยคุณไม่ได้เป็นอยู่คนเดียว ผมก็เป็นและอีกหลายๆ คนก็เป็นครับ ซึ่งความรู้สึกแบบนี้ ส่วนตัวผมเองก็ปล่อยมันไว้นานมาก แต่ก็รู้สึกว่าตัวเองยุ่งมากทั้งงานหลวง งานเสริม งานเพื่อสังคม มันอยู่ในทุกช่วงเวลาของชีวิตตั้งแต่ตื่นนอน จนนอนหลับ เรื่อยไปจนเสาร์ อาทิตย์ จนแทบไม่เคยได้อยู่กับตัวเอง\u003c/p\u003e\n\u003cp\u003eผมเป็นอย่างนั้นมาตลอด หลายเดือนมากจนกระทั่งช่วงต้นเดือนพฤศจิกายนที่ผ่านมาผมป่วย ซึ่งตอนแรกเหมือนจะหายเร็ว เอาไปเอามากินเวลาไป 2 สัปดาห์เต็มๆ กว่าจะดีขึ้น ซึ่ง 2 สัปดาห์ที่นอนป่วย ที่ต้องพักผ่อน ให้ยาผ่านสายน้ำเกลือ เป็นครั้งแรกในรอบหลายเดือนเลยที่ผมได้หยุดจริงๆ คำว่าหยุดผมหมายถึงทุกอย่างที่ผมบอกว่าผมยุ่งมาก ทั้งงานหลวง งานเสริม งานเพื่อสังคม ทุกอย่างหยุดหมด\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/make-time/MXGIjWIr1_hu_2218143e0ed271c8.webp\"\n       srcset=\"/make-time/MXGIjWIr1_hu_e1a79c79419a26c6.webp 480w, /make-time/MXGIjWIr1_hu_2218143e0ed271c8.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"801\"\n       alt=\"147649.jpg\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eในช่วงเวลานั้นแรกๆ สิ่งที่ผมทำนอกจาก กินกับนอน คือไถมือถือไปเรื่อยๆ ไถจนแอพมันล็อกแล้วแจ้งเตือนว่า Digital balance วันนี้หมดแล้วนะ ช่วงแรกๆ ผมก็กด ignore มันไปแล้วก็ไถๆ ต่อจนนอน วนอยู่อย่างนี้หลายวัน จนวันนึงเหมือนผมก็ตั้งคำถามกับตัวเองว่า ทำอะไรอยู่วะ แล้วผมซึ่งหยิบ Kindle มาด้วยพอดีก็เปิดหนังสือ Make Time ขึ้นมาอ่านอีกครั้ง หลังจากที่เคยอ่านเมื่อหลายปีมาแล้ว แล้วผมค้นพบว่า มันกลับมาหาผมได้ถูกช่วงเวลาชีวิตมาก\u003c/p\u003e","title":"Make Time | โลกมันวุ่นวาย แต่เรายังหาความสงบได้นะ"},{"content":"ช่วง 2 เดือนที่ผ่านมาเป็นช่วงเวลาที่ผมเริ่มหัดใช้ Emacs จาก 0 เลยซึ่งจากใจคนที่อยู่บน Vim และ Jetbrains ecosystem มานาน ผมค้นพบว่า มันมีหลายๆ อย่างมากที่ Emacs ทำได้ดีในแบบของมันและหลายๆ ครั้งเป็นแรงบันดาลใจให้โปรแกรมอื่นๆ ด้วย\nและจากชื่อที่มี EP1 แน่นอนครับว่า ผมไม่ได้มาเดี่ยวๆ เดี๋ยวมันจะพาลูกตามมาอีกเรื่อยๆ ก็คอยกดติดตามซีรีย์นี้กันได้ครับ สำหรับในตอนแรกนี้ ผมจะเล่าถึงวิธีการ ที่ผมศึกษาวิธีใช้ Emacs ในช่วงที่ผ่านมาครับ ซึ่งถ้าใครขี้เกียจรอตอนต่อๆ ไป ถ้าดูตามวาร์ปที่ผมลิสต์ไว้ก็ไปได้ไกลละครับ\nอย่างแรกเลยวิธีติดตั้ง Emacs ใน Mac เหมือนจะง่ายแต่ต้องรู้ ปกติเวลาเราจะลง Software อะไรใน Mac ถ้าแบบไม่คิดเลย เราจะมุ่งไปหา Homebrew ซึ่งแค่ brew install emacs แค่นี้ก็ใช้ได้ละ แต่ปัญหาคือ Binary นี้มันไม่ได้ถูก Optimize มาให้ Mac ซักเท่าไร จะเจอปัญหาปุ่ม Command บ้าง แต่ที่หนักที่สุดคือ Window mode นี่แหละ ซึ่งผมผู้ใช้งาน Magnet อยู่ทำงานกับ Emacs ด้วยไม่ได้ เพราะ Window Snapping ไม่ทำงาน (link)\nสุดท้าย เลยจึงเป็นสาเหตุให้ต้องหา Binary Emacs ใหม่ ซึ่งผมมาจบที่ Homebrew-emacsmacport ซึ่งแก้ปัญหา GUI support ใน Mac มาให้แล้ว ตัวนี้สามารถลงผ่าน Homebrew หรือโหลด pre-built binary มาได้เหมือนกัน แต่ผมแนะนำลงผ่าน Homebrew เพราะนอกจากจะอัพเกรดง่ายกว่าแล้ว เรายังสามารถ custom install ได้เช่น เปลี่ยนไอคอนของ App Emacs เป็นต้น\nสรุปวิธีติดตั้ง Emacs บน Mac COPY\n$ brew tap railwaycat/emacsmacport $ brew install emacs-mac --with-emacs-big-sur-icon จุดเริ่มต้นจริงๆ ส่วนตัวผมเป็น Vim User มาน่าจะเกิน 10 ปีละ เคยเฉียดมาใกล้ Emacs มากที่สุดตอนใช้ Spacemacs เมื่อหลายปีก่อน แต่ด้วยความที่ตอนนั้นก็ใช้ Evil mode ในนั้น เลยยังไม่ค่อยได้สัมผัสกับพลังของมันเท่าไร key-binding ที่ใช้ก็เหมือนใช้ Vim ปกติเลย\nมารอบนี้จุดเริ่มต้นเพราะคลาส Programming Languages, Part A ซึ่งในคลาสแนะนำให้ใช้ Emacs เพราะมันสะดวกกับการเขียน sml มากกว่า ซึ่งตอนเรียนๆ อาจารย์ก็ไม่ได้ใช้อะไรมากนอกจาก navigate ใน Emacs ซึ่งเราก็สามารถใช้ลูกศรได้ตามปกติเลย แต่ถ้าจะมีพิเศษหน่อยคือ การสั่ง Evaluate sml expression (C-c C-e) หรือการเปิด REPL ของ sml เลย ซึ่งใช้ง่ายมาก เลยเป็นจุดเริ่มต้นที่ผมเริ่มจะไปลงลึกกับ Emacs ละ\nด้วยความที่ในคลาสไม่ได้สอนใช้นอกจากที่ผมบอกข้างต้น วิธีการเรียน Emacs ผมช่วงแรกเลยเรียนกับ Youtube channel: System Crafters ซึ่งเป็นช่องที่มีแต่ Emacs จริงๆ จุดเริ่มต้นผมอยู่ที่วิดีโอ The Absolute Beginner\u0026rsquo;s Guide to Emacs ซึ่งผมรู้จัก dired เข้าใจแนวคิด Window/Frame/Buffer แนวคิดของ Major-Mode, Minor-Mode แนวคิดของ Command กับพวก Key binding พื้นฐานจากวิดีโอนี้เลย\nพอจบจากตรงนี้ชีวิตก็เริ่มซนขึ้น เพราะใน Vim เราสามารถ Custom อะไรต่างๆ ได้ลง Package เพิ่มได้ เราก็อยากทำแบบเดียวกันได้เหมือนกัน เลยไปต่อที่วิดีโอซีรีย์ Emacs From Scratch ซึ่งสอนเราค่อยๆ custom ไฟล์ init.el ขึ้นมาจาก 0 เลย ซึ่งซีรีย์นี้ทำให้ผมค่อยๆ รู้จักกับ Ecosystem ของ Emacs มากขึ้นเรื่อยๆ ว่าเห้ย มันมีอะไรมากกว่านั้นนะ และ Community ชอบใช้อะไรกันได้เร็วมาก ซึ่งในแต่ละตอนจะมี Org note เก็บไว้ที่ GitHub ของเค้าด้วย ซึ่งแยกเป็นตอนๆ แบบละเอียด พร้อมคำอธิบายเลย ซึ่งผมบอกได้เลยว่า ใครชอบอ่านไป GitHub ใครชอบดูวิดีโอไป Youtube เลยครับ ได้อะไรจากตรงนี้เยอะมากแน่ๆ\nตอนแรกขอหอมปาก หอมคอแค่นี้ก่อน ส่วนตอนต่อไปจะเล่าถึงอะไรนั้น คอยติดตามกันได้ครับ\n","permalink":"https://yothinix-com.pages.dev/emacs-getting-start/","summary":"\u003cp\u003eช่วง 2 เดือนที่ผ่านมาเป็นช่วงเวลาที่ผมเริ่มหัดใช้ Emacs จาก 0 เลยซึ่งจากใจคนที่อยู่บน Vim และ Jetbrains ecosystem มานาน ผมค้นพบว่า มันมีหลายๆ อย่างมากที่ Emacs ทำได้ดีในแบบของมันและหลายๆ ครั้งเป็นแรงบันดาลใจให้โปรแกรมอื่นๆ ด้วย\u003c/p\u003e\n\u003cp\u003eและจากชื่อที่มี EP1 แน่นอนครับว่า ผมไม่ได้มาเดี่ยวๆ เดี๋ยวมันจะพาลูกตามมาอีกเรื่อยๆ ก็คอยกดติดตามซีรีย์นี้กันได้ครับ สำหรับในตอนแรกนี้ ผมจะเล่าถึงวิธีการ ที่ผมศึกษาวิธีใช้ Emacs ในช่วงที่ผ่านมาครับ ซึ่งถ้าใครขี้เกียจรอตอนต่อๆ ไป ถ้าดูตามวาร์ปที่ผมลิสต์ไว้ก็ไปได้ไกลละครับ\u003c/p\u003e\n\u003ch2 id=\"อยางแรกเลยวธตดตง-emacs-ใน-mac-เหมอนจะงายแตตองร\"\u003e\u003cstrong\u003eอย่างแรกเลยวิธีติดตั้ง Emacs ใน Mac เหมือนจะง่ายแต่ต้องรู้\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eปกติเวลาเราจะลง Software อะไรใน Mac ถ้าแบบไม่คิดเลย เราจะมุ่งไปหา Homebrew ซึ่งแค่ brew install emacs แค่นี้ก็ใช้ได้ละ แต่ปัญหาคือ Binary นี้มันไม่ได้ถูก Optimize มาให้ Mac ซักเท่าไร จะเจอปัญหาปุ่ม Command บ้าง แต่ที่หนักที่สุดคือ Window mode นี่แหละ ซึ่งผมผู้ใช้งาน Magnet อยู่ทำงานกับ Emacs ด้วยไม่ได้ เพราะ Window Snapping ไม่ทำงาน (\u003ca href=\"https://www.reddit.com/r/emacs/comments/8ez3a9/macos_window_snapping_with_magnetdoesnt_work_on/\"\u003elink\u003c/a\u003e)\u003c/p\u003e","title":"Emacs diary EP1: จุดเริ่มต้น"},{"content":"ไปเจอ Repository นี้มาใน GitHub ครับ เป็นการตีความ Principles of Good Design ในตำนานของ Dieter Rams ในมุมของ Software Engineering ซึ่งมีอยู่ 10 ข้อด้วยกัน ผมเห็นว่าน่าสนใจดี เลยแปลมาฝากกัน\n\\1.ซอฟท์แวร์ที่ดีต้องเป็นนวัตกรรม (Good software is innovative) ปรับปรุงซอฟท์แวร์เก่าด้วยเทคโนโลยีใหม่ๆ หรือสร้างซอฟท์แวร์ใหม่ด้วยเทคโนโลยีที่มีอยู่แล้ว\nจงพยายามที่จะสร้างสรรรค์สิ่งใหม่แก่โลกใบนี้ ถึงแม้สิ่งนั้นจะเป็นการลอกจากสิ่งที่มีอยู่ สังเกตุผู้ใช้เพื่อหาแรงบันดาลใจและพยายามทายใจว่าเขาอยากได้อะไรต่อไป\n\\2.ซอฟท์แวร์ที่ดีต้องมีประโยชน์ (Good software is useful) ซอฟท์แวร์ต้องมีค่ากับผู้ใช้ มันควรทำให้เขามีชีวิตที่ดีกว่าเดิมโดยการเติมเต็มสิ่งที่ขาดหรือแก้ปัญหาให้กับเขา เราควรเก็บข้อมูลว่าซอฟท์แวร์เรามีค่ากับผู้ใช้งานเท่าไรอยู่เสมอ เพื่อทำให้มันมีค่าต่อๆ ไป\n\\3.ซอฟท์แวร์ที่ดีต้องมีศิลปะ (Good software is aesthetic) ลองถอยกลับมาดูโค้ดของเราบ้าง มันควรดูงดงามในมุมมองของเรา ความงดงามนั้นบ่อยครั้งเกิดจากคุณสมบัติหลายๆ อย่างรวมกันขึ้นมาทำให้โค้ดที่งดงามต่อเรานั้นมักจะมีความ เข้าใจง่าย เป็นไปตามหลัก(ภาษา) และอธิบายตัวมันเอง ซึ่งเราในฐานะโปรแกรมเมอร์ให้คุณค่ากับสิ่งเหล่านี้\n\\4.ซอฟท์แวร์ที่ดีต้องเข้าใจได้ (Good software is understandable) โค้ดนั้นไม่เทพ ถ้าไม่มีใครสามารถเข้าใจมันได้ โค้ดเทพมักจะทำให้เราเกิดคำถามและข้อสงสัย โค้ดที่เข้าใจได้ต้องตรงไปตรงมากับคนอื่นและแม้แต่ตัวเราในอนาคต มันควรจะเขียนขึ้นมาโดยนึกถึงความเข้าใจของคนดูแลก่อนเสมอ ตามด้วยเครื่องจักร\n\\5.ซอฟท์แวร์ที่ดีต้องตรงไปตรงมา (Good software is honest) เลี่ยงที่จะตั้งนามธรรม (abstraction) ที่เราไม่ต้องการ เลี่ยงที่จะห่อทุกอย่างโดยไม่คิด พยายามทำความเข้าใจเหตุผลของทุกอย่างก่อนที่เราจะเขียนมันไปเป็นโค้ด กล้าที่จะเปิดเผย ตัววัดคุณภาพซอฟท์แวร์ที่คุณรู้สึกลำบากใจเช่น ความครอบคลุมของชุดทดสอบและสิ่งที่เราไม่ควรทำ ทำให้สิ่งเหล่านี้หยุดยั้งการสร้างซอฟท์แวร์ของเรา เพื่อที่เราจะได้หาเวลาหรือความช่วยเหลือมาเก็บกวาดสิ่งเหล่านี้\n\\6.ซอฟท์แวร์ที่ดีต้องไม่น่ารำคาญ (Good software is unobtrusive) จงอย่ายั้งมือในการลดอุปสรรคต่างๆ ระหว่างผู้ใช้กับคุณค่าที่เขาจะได้รับจากซอฟท์แวร์ของเรา\nซอฟท์แวร์ที่ออกแบบมาดีมักจะถูกพิสูจน์ความคาดหวังของผู้ใช้มาก่อนหน้านี้เป็นจำนวนมาก จงหมั่นสังเกตุปฏิกิริยาผู้ใช้ พยายามบันทึกอุปสรรคและความอึดอัดต่างๆ จากการใช้งาน จำไว้เสมอว่าคำติชมเหล่านี้เป็นข้อมูลที่ล้ำค่ามากและจงใช้มันแบบไม่ลำเอียง\n\\7.ซอฟท์แวร์ที่ดีต้องยั่งยืน (Good software is long-lasting) ปกป้องอนาคตของซอฟท์แวร์เราโดยการวางแผนสำหรับส่วนต่างๆ ที่เราอาศัยอยู่เช่น เบราว์เซอร์หรือระบบปฏิบัติการ ที่มีการปรับเปลี่ยนอยู่ตลอดอายุการใช้งาน หลีกเลี่ยงการผูกอยู่กับเทคโนโลยีที่ถูกทิ้งได้และถ้าเป็นไปได้พยายามพ่วงสิ่งที่เราต้องพึ่งพาไว้ในซอฟท์แวร์เราด้วย เพื่อเป็นการปกป้องการเปลี่ยนแปลงต่อสิ่งเหล่านี้ พิจารณาการปล่อยโค้ดภายใต้ข้อตกลงที่เปิดกว้าง เพื่อที่มันสามารถจะถูกสร้างและอยู่ร่วมกับแพลทฟอร์มใหม่ในอนาคตได้อย่างมีความสุข\n\\8.ซอฟท์แวร์ที่ดีต้องถูกคิดมาอย่างถี่ถ้วน (Good software is thorough down to the last detail) พยายามคิดให้เยอะเกี่ยวกับทุกการกระทำของซอฟท์แวร์ของเราและทำให้มั่นใจได้ว่าทุกๆ ข้อผิดพลาดถูกจัดการและทำความเข้าใจมาแล้ว เช่น ข้อผิดพลาดในหน่วยความจำหรือตัวเก็บข้อมูลไม่พอ ข้อผิดพลาดจากการทำงานผิดเงื่อนไข ข้อผิดพลาดที่เกิดจากระบบเครือข่าย การมีสิทธิเข้าถึงที่ไม่เพียงพอ เป็นต้น\nซึ่งไม่ต่างจากการเล่นหมากรุกแข่งกับตัวเองเลย เพราะฉะนั้นพยายามสร้างพื้นที่ให้เราได้ทดลองข้อผิดพลาดต่างๆ ขึ้นมาให้ได้ก่อนเสมอ จงอย่าโอนอ่อนกับซอฟท์แวร์ของเราเหมือนกับที่เราไม่อ่อนข้อกับคนอื่นๆ\n\\9.ซอฟท์แวร์ที่ดีต้องเป็นมิตรกับสิ่งแวดล้อม (Good software is environmentally friendly) จงหลีกเลี่ยงการใช้ทรัพยากรไปโดยเปล่าประโยชน์ เราควรพิจารณาถึงรูปแบบการใช้พลังงานของซอฟท์แวร์เราในขณะที่มันเติบโตขึ้น จงใช้แค่เท่าที่จำเป็นและคืนส่วนที่เกินมากลับไป ถ้าซอฟท์แวร์เราไม่ได้กำลังทำอะไรที่มันมีประโยชน์อยู่ ตัวมันเองก็ไม่ควรจะกินทรัพยากรนั้นและอยู่แบบเฉื่อยๆ ไป\n\\10.ซอฟท์แวร์ที่ดีต้องมีขนาดเล็กเท่าที่จะทำได้ (Good software is as little software as possible) โค้ดน้อยย่อมดีกว่าเสมอ พยายามทำให้โค้ดมีขนาดกระชับแต่ยังเข้าใจได้ แม้แต่คอมเมนต์ก็ไม่มีข้อแม้\nพยายามต่อต้านการทำอะไรที่ใหญ่เกินความจำเป็น เมื่อถึงจุดที่ซอฟท์แวร์เรา \u0026ldquo;เกือบที่จะดีพอ\u0026rdquo; เมื่อนั้นแหละคือเสร็จ ความหมายของคำว่าเสร็จมาจาก 1) ปราศจากข้อบกพร่อง 2) ทำงานสอดคล้องกับความต้องการ 3) มีสมรรถนะตามที่ต้องการ ซึ่งเราต้องการทั้งสามข้อนี้เลย และถึงแม้ว่ามันจะตามมาด้วยสิ่งที่ต้องทำเยอะมาก แต่ก็ไม่มากเกินกว่านี้อีกแล้ว\nที่มา: github.com/zedr/dieter-rams-10-applied-to-s.. ภาพประกอบจาก: behance.net/gallery/82670287/Dieter-Rams-10.. ","permalink":"https://yothinix-com.pages.dev/aepl-dieter-rams-principles-of-good-design-applied-to-software-engineering/","summary":"\u003cp\u003eไปเจอ Repository นี้มาใน GitHub ครับ เป็นการตีความ Principles of Good Design ในตำนานของ Dieter Rams ในมุมของ Software Engineering ซึ่งมีอยู่ 10 ข้อด้วยกัน ผมเห็นว่าน่าสนใจดี เลยแปลมาฝากกัน\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"1ซอฟทแวรทดตองเปนนวตกรรม-good-software-is-innovative\"\u003e\\1.ซอฟท์แวร์ที่ดีต้องเป็นนวัตกรรม (Good software is innovative)\u003c/h3\u003e\n\u003cp\u003eปรับปรุงซอฟท์แวร์เก่าด้วยเทคโนโลยีใหม่ๆ หรือสร้างซอฟท์แวร์ใหม่ด้วยเทคโนโลยีที่มีอยู่แล้ว\u003c/p\u003e\n\u003cp\u003eจงพยายามที่จะสร้างสรรรค์สิ่งใหม่แก่โลกใบนี้ ถึงแม้สิ่งนั้นจะเป็นการลอกจากสิ่งที่มีอยู่ สังเกตุผู้ใช้เพื่อหาแรงบันดาลใจและพยายามทายใจว่าเขาอยากได้อะไรต่อไป\u003c/p\u003e\n\u003ch3 id=\"2ซอฟทแวรทดตองมประโยชน-good-software-is-useful\"\u003e\\2.ซอฟท์แวร์ที่ดีต้องมีประโยชน์ (Good software is useful)\u003c/h3\u003e\n\u003cp\u003eซอฟท์แวร์ต้องมีค่ากับผู้ใช้ มันควรทำให้เขามีชีวิตที่ดีกว่าเดิมโดยการเติมเต็มสิ่งที่ขาดหรือแก้ปัญหาให้กับเขา เราควรเก็บข้อมูลว่าซอฟท์แวร์เรามีค่ากับผู้ใช้งานเท่าไรอยู่เสมอ เพื่อทำให้มันมีค่าต่อๆ ไป\u003c/p\u003e\n\u003ch3 id=\"3ซอฟทแวรทดตองมศลปะ-good-software-is-aesthetic\"\u003e\\3.ซอฟท์แวร์ที่ดีต้องมีศิลปะ (Good software is aesthetic)\u003c/h3\u003e\n\u003cp\u003eลองถอยกลับมาดูโค้ดของเราบ้าง มันควรดูงดงามในมุมมองของเรา ความงดงามนั้นบ่อยครั้งเกิดจากคุณสมบัติหลายๆ อย่างรวมกันขึ้นมาทำให้โค้ดที่งดงามต่อเรานั้นมักจะมีความ เข้าใจง่าย เป็นไปตามหลัก(ภาษา) และอธิบายตัวมันเอง ซึ่งเราในฐานะโปรแกรมเมอร์ให้คุณค่ากับสิ่งเหล่านี้\u003c/p\u003e\n\u003ch3 id=\"4ซอฟทแวรทดตองเขาใจได-good-software-is-understandable\"\u003e\\4.ซอฟท์แวร์ที่ดีต้องเข้าใจได้ (Good software is understandable)\u003c/h3\u003e\n\u003cp\u003eโค้ดนั้นไม่เทพ ถ้าไม่มีใครสามารถเข้าใจมันได้ โค้ดเทพมักจะทำให้เราเกิดคำถามและข้อสงสัย โค้ดที่เข้าใจได้ต้องตรงไปตรงมากับคนอื่นและแม้แต่ตัวเราในอนาคต มันควรจะเขียนขึ้นมาโดยนึกถึงความเข้าใจของคนดูแลก่อนเสมอ ตามด้วยเครื่องจักร\u003c/p\u003e\n\u003ch3 id=\"5ซอฟทแวรทดตองตรงไปตรงมา-good-software-is-honest\"\u003e\\5.ซอฟท์แวร์ที่ดีต้องตรงไปตรงมา (Good software is honest)\u003c/h3\u003e\n\u003cp\u003eเลี่ยงที่จะตั้งนามธรรม (abstraction) ที่เราไม่ต้องการ เลี่ยงที่จะห่อทุกอย่างโดยไม่คิด พยายามทำความเข้าใจเหตุผลของทุกอย่างก่อนที่เราจะเขียนมันไปเป็นโค้ด กล้าที่จะเปิดเผย ตัววัดคุณภาพซอฟท์แวร์ที่คุณรู้สึกลำบากใจเช่น ความครอบคลุมของชุดทดสอบและสิ่งที่เราไม่ควรทำ ทำให้สิ่งเหล่านี้หยุดยั้งการสร้างซอฟท์แวร์ของเรา เพื่อที่เราจะได้หาเวลาหรือความช่วยเหลือมาเก็บกวาดสิ่งเหล่านี้\u003c/p\u003e","title":"[แปล] Dieter Rams' principles of good design applied to software engineering"},{"content":"ใน ตอนที่แล้ว เราพูดถึงคีย์บอร์ด Ergodox EZ ไปแล้ว ในตอนนี้ผมจะมาพูดถึงตัว Dvorak Keyboard Layout บ้างในตอนนี้ว่าทำไม ผมถึงเลือกใช้ตัวนี้และผมเดาว่าหลายๆ คนน่าจะมีคำถามว่า เปลี่ยนแล้วพิมพ์เร็วขึ้นเหรอ เดี๋ยวผมจะมาตอบคำถามในตอนนี้นะครับ\nDvorak ก่อนอื่น ถ้าใครเคยสังเกตุคีย์บอร์ดที่เราใช้อยู่กันปกติ ถ้าเป็นแป้นภาษาอังกฤษจะอยู่บนพื้นฐานของ Layout ชื่อว่า QWERTY ครับ ซึ่งใช้มาตั้งแต่ยุคเป็นเครื่องพิมพ์ดีดมา ซึ่งลือกันว่าที่ Layout ถูกวางแบบนี้เพื่อที่จะให้แป้นพิมพ์ขัดกันน้อยที่สุดในยุคนั้นครับ แต่จริงๆ เรื่องนี้มีอะไรมากกว่านั้นครับ ถ้าลอง Search ดูจะสนุกมาก แต่ไม่ใช่ประเด็นหลักที่ผมจะมาเล่าวันนี้\nDvorak Heat map จาก daskeyboard.com/blog/the-dvorak-keyboard-la..\nข้ามเรื่อง QWERTY มาจนปี 1932 August Dvorak ได้เปิดตัว Dvorak Simplified Keyboard โดยออกแบบมาเพื่อลดความผิดพลาด, เพิ่มความเร็วและลดความเมื่อยล้าที่เกิดจากการพิมพ์ครับ โดยศึกษาจากความถี่ของตัวอักษรที่ถูกพิมพ์ในภาษาอังกฤษ ฟีเจอร์หลักๆ จะมี\nนำเอาตัวอักษรที่พิมพ์บ่อยที่สุดมาไว้ใน home row ทำให้เรา ไม่ต้องขยับนิ้วขึ้นลงบ่อยๆ เหมือน QWERTY ตัวสระในภาษาอังกฤษทั้งหมดก็อยู่ใน home row ด้วยครับ ตัวอักษรที่พิมพ์บ่อยๆ Dvorak จะย้ายมันไปอยู่ top row แทน bottom row ครับ เพราะเชื่อว่า เราสามารถยกนิ้วขึ้นไปพิมพ์ได้ง่ายกว่ากดนิ้วลงมาใน bottom row โดยอัตราส่วนในการพิมพ์ของแต่ละ row (top-home-bottom) ของ Dvorak จะอยู่ที่ 22% - 70% - 8% เทียบกับ QWERTY ซึ่งอยู่ที่ 52% - 32% - 16%\nทำไมถึงไม่ไป Colemak หรือ Workman หรือ \u0026hellip; ต้องบอกว่านี่เป็นจุดที่ตัดสินใจยากมากๆ จุดนึงเลย เพราะคนที่ผมรู้จักรอบตัวมีทั้ง Dvorak กับ Colemak และฝั่ง Colemak จะบอกเป็นเสียงเดียวกันว่า เปลี่ยนแค่ 17 ปุ่มเองนะ ซึ่งหลังจาก ชั่งน้ำหนักกับหาข้อมูลหนักมากในช่วงนั้นมี 2 เหตุผลหลักๆ ที่ผมเลือกมา Dvorak\nเหตุผลแรกคือ Programmer Dvorak ซึ่งเป็นอีก Layout นึง แต่สุดท้ายแล้วผมไม่ได้ไปถึงตรงนั้น เพราะมันประหลาดจริงๆ (ลองไปดูแถวตัวเลขได้) แต่ผมได้ยินมาจากซักคลิปใน Youtube นี่แหละว่า Dvorak มันเหมาะกับการเขียนโปรแกรมกว่า เพราะมันย้าย underscore มาไว้ตรงนิ้วก้อย ซึ่งเป็นหนึ่งในปุ่มที่กดบ่อยที่สุดเวลาเขียนโปรแกรม (ที่แน่ๆ Python ที่ใช้ snake case เป็นหลักภาษานึงละ) อีกปุ่มนึงที่ผมใช้บ่อยตามมาพอกันคือ comma กับ dot ซึ่งพอย้ายไปอยู่ top row ความเห็นส่วนตัวคือมันกดสบายกว่าเยอะเลย จะมีปุ่มเดียวที่ผมไม่ค่อยโอเคเท่าไรคือ semi-colon ที่อยู่ที่นิ้วก้อยซ้าย bottom row\nเหตุผลที่สองคือ ข้อได้เปรียบหลายๆ อย่างของ Colemak มันไม่มีประโยชน์ในตอนที่ผมเปลี่ยนมาใช้ Ergodox อยู่ดี อย่างเช่นเปลี่ยนแค่ 17 ปุ่ม แต่ผมเปลี่ยน layout ขอบๆ แทบจะทั้งหมด หรือเคสที่ปุ่ม copy / paste อยู่ตำแหน่งเดิม ผมก็ไม่ได้ใช้ เพราะแมพปุ่ม copy/paste ในปุ่มใหม่เลย\nLearning Process ทีนี้พอตัดสินใจเลือกได้แล้ว ก็ถึงเวลาฝึก ถ้าเราดูหลายๆ ที่จะแนะนำให้ไปฝึกที่เว็บ https://learn.dvorak.nl/ ซึ่งผมลองอยู่แปปนึงแล้วก็คิดว่า เออมันไม่สนุกเลยจนผมไปเจอเว็บ TypingClub ซึ่งมีบทเรียนทั้ง Dvorak และ Colemak เลย\nซึ่งการเรียนใน TypingClub ออกแบบมาดีมากๆ คือ นอกจากค่อยๆ เทรน muscle memory เราให้แต่ละนิ้วก้าวออกไปอย่างที่มันควรจะเป็นแล้ว ในแต่ละบทยังมีเกมให้เราเล่นด้วย ซึ่งช่วงแรกๆ ผมเรียนรัวๆ มากพอเรียนครบทุก row แล้วบทเรียนจะค่อยๆ เปลี่ยนให้เราเพิ่ม Speed + Accuracy ตามมาครับ โดยพิมพ์เป็นบทความมากขึ้นคล้ายๆ กับที่เราพิมพ์ใน MonkeyType แต่ว่าบทความจะคัดมาให้เหมาะกับเรื่องที่เราต้องฝึกเลย และก่อนเข้าบทความก็จะสอน combo ที่เจอบ่อยๆ ให้เราพิมพ์ rolling finger ได้ง่ายขึ้นเช่น est, ing, the อะไรพวกนี้ครับ จังหวะตอนเรียนช่วงนี้เหมือนร่ายมนต์มาก\nช่วงแรกๆ ที่พิมพ์ได้แค่ 10+ wpm นี่เจ็บปวดมาก แต่ก็ค่อยๆ ดีขึ้นตามเวลาครับ\nนอกจาก TypingClub ช่วงแรกใช้ 3 layout (en-QWERTY, en-Dvorak, th-QWERTY) ตอนกลางวันทำงานก็จะใช้ QWERTY แต่พอค่ำๆ เลิกงานก็จะสลับมา Dvorak เพราะว่าช่วงที่ความเร็วตกมันแทบจะทำให้ทำงานอะไรไม่ได้เลย ตอนที่พิมพ์ยังไม่ถึง 40 wpm อีกอย่างที่ช่วยคือ ตอนเช้าๆ สิ่งแรกที่ทำหลังจากเปิดคอมคือ มาพิมพ์ประโยค The quick brown fox jumps over the lazy dog ทุกวัน ประโยคนี้เป็น Pangram ให้ฝึกนิ้วเราไปทุกๆ ตัวอักษร ซึ่งผมได้มาตอนฝึก Calligraphy หลายปีละ\nแต่จุดเปลี่ยนจริงๆ ของการปรับมาใช้อยู่ที่วันที่คีย์บอร์ดเก่าผมพัง จังหวะพอดีมากๆ ที่พิมพ์ได้ประมาณ 40 wpm อยู่ดีๆ ก็พิมพ์ไม่ติด แล้ว flash firmware ไม่ได้เลยต้องบอกลาตัวเก่า แล้วสลับมาใช้ Ergodox เต็มตัว และด้วยความที่ไม่เคยฝึกพิมพ์ QWERTY ใน Ergodox มาก่อนเลย เพราะฉะนั้นมันเลยบังคับตัวเองให้ใช้แค่ 2 layout คือ en-Dvorak และ th-QWERTY ครับ\nแล้วภาษาไทยหละ ส่วนตัวผมเคยเรียนพิมพ์สัมผัสภาษาไทยตั้งแต่เด็กมากๆ เลยเลือกที่จะยังอยู่บน QWERTY อยู่ครับ แล้วตัวอักษรส่วนใหญ่ยังครอบคลุมได้ใน Ergodox จะมีพวกตัวที่อยู่กับ - = [ ] ซึ่งตรงกับ ข ช บ ล ที่ต้องมาฝึกใหม่ให้หัดมาใช้นิ้วโป้ง ในการกดปุ่มพวกนี้แทน ซึ่งเอาจริงๆ ก็ใช้เวลาแค่ 2 - 3 สัปดาห์ ก็ปรับตัวได้แล้วครับ\nจะมีที่น่ารำคาญนิดหน่อยคือ ด้วยความที่ผมแมพ Ergodox ให้ Layer เป็น Dvorak เลย พอจะเปลี่ยนมาใช้ QWERTY ก็ต้อง switch มาอีก layer แล้วต้องเปลี่ยน input language จากภาษาไทยเป็นอังกฤษด้วย ตอนนี้เลยต้องกด 2 ปุ่มคือ ปุ่ม switch layer + ปุ่ม switch language ซึ่งก็ลำบากพอๆ กับตอนใช้คีย์แมคปกติที่กด cmd + space\nซึ่งช่วงแรกๆ ตอนก่อนคีย์บอร์ดพังยังไม่ย้ายมา Dvorak เต็มตัว Layer หลักจะยังเป็น QWERTY อยู่ แต่พอเริ่มอยู่บน Dvorak ได้อย่างปกติสุขแล้ว ก็เปลี่ยน Layer หลักมาเป็น Dvorak และ Layer รองเป็น QWERTY แทนชีวิตก็ง่ายขึ้นเยอะเลย\nมันไม่ใช่แค่ Layout เปลี่ยนแต่ Muscle Memory ด้วย สิ่งที่ผมมาเรียนรู้อย่างนึงพอต้องมาปรับ Layout คือ เราไม่ได้ใช้คีย์บอร์ดแค่พิมพ์คำหรือประโยค แต่มันคือ Input แทบทั้งหมด ซึ่งรวมถึงคีย์ลัดในโปรแกรมต่างๆ อย่าง Text Editor, Browser, Terminal ด้วย ซึ่งแม้กระทั่ง command ง่ายๆ ที่เราเคยใช้ทุกๆ วันอย่าง ls, cd หรือพวก git shortcut ใน zsh อย่าง gst, gd อะไรพวกนี้ต้องมาฝึกกล้ามเนื้อใหม่ด้วย ซึ่งกว่าจะปรับมาคืนได้ อันนี้ก็เกือบๆ เดือนเต็มๆ ครับ\nที่หนักที่สุดและฉิบหายวายป่วงที่สุดสำหรับผมคือการที่ผมเป็นชาว Vim นี่แหละ เพราะว่า Muscle memory ของ Vim จะอยู่บน QWERTY หมดเลย ซึ่งแรกๆ ผมใช้วิธีถ้าอยู่ใน Normal mode จะสลับ layout เป็น QWERTY แล้วถ้า Input ค่อยเปลี่ยนเป็น Dvorak แต่ทำแบบนั้นได้ไม่นานก็รู้สึกว่า ชีวิตมันยากเกินไป เพราะเราต้องจำ 2 state ในหัวคือ state ของ layout กับ state ของ Vim mode ไปพร้อมๆ กัน ซึ่งเละเทะมาก จนผมแทบจะเลิกใช้ Vim ไปเลย\nจนกระทั่งตอนที่ผมเริ่มจะ comfort กับ Dvorak จริงๆ ช่วงที่อยู่ประมาณ 60 wpm เป็นช่วงที่ผมเริ่มจะกลับมาฝึกใช้ Vim กับ Dvorak อีกรอบนึง แล้วปรับให้ home row มือขวาใน Layer navigation ของคีย์บอร์ดเป็นลูกศรเรียงแบบ h j k l ใน Vim normal mode และเริ่มฝึก Vim ใหม่กับปุ่มบน Dvorak ซึ่งก็มีดีๆ หลายที่เลยเช่น จะเข้า insert mode กด i มันใกล้มือมากแล้วอยู่ใน home row หรืออย่าง w b ที่เป็น word jump ก็อยู่ใกล้กันมากขึ้น แต่พวก chord ที่เคยกด combo กันอย่าง DT + char พวกนี้ประสบปัญหาเดียวกับ command ใน Terminal ข้างบนเลยคือต้องฝึกใหม่หมด\nสรุป กลับมาตอบคำถามที่ผมทิ้งไว้อันแรกข้างบนคือ พิมพ์เร็วขึ้นมั้ย ผมต้องบอกตามตรงว่าผมยังพิมพ์ไปไม่ถึงความเร็วเฉลี่ยที่ผมพิมพ์ได้ใน QWERTY ที่ 90+ wpm โดยตอนนี้ก็ยังอยู่ได้แค่ที่ 70 - 80 wpm เลยต้องฝึกไปอีกซักพักครับ แต่ถ้ามีจุดต่างแน่ๆ ในมุมของการพิมพ์สัมผัสคือมันเมื่อยน้อยลงอย่างรู้สึกได้ แล้วข้อมือผมไม่ต้องยกบ่อยๆ ถ้าเทียบกับตอนพิมพ์บน QWERTY และก็นิ้วกวาดไปทั่วคีย์บอร์ดอย่างบ้าคลั่ง พอสลับมาใช้ Dvorak แล้วเคยอัด Timelapse ไว้ตอนเรียน HtDP เห็นว่านิ้วตัวเองอยู่ใน Home row เยอะมาก\nตอนนี้ก็น่าจะจบประมาณนี้ก่อน ส่วนตอนหน้าเป็นตอนสุดท้ายผมจะมาเล่าสิ่งที่ได้เรียนรู้นอกจากที่ผมเล่ามาตลอด 2 ตอนด้วย จะเป็นยังไงก็คอยติดตามต่อกันได้ครับ ถ้าใครชอบบทความสามารถกด subscribe ได้ในช่องข้างล่างเลยครับ หรือจะกดไลค์เพจ เขียนงูให้วัวกลัว ก็ได้ แล้วเจอกันใหม่ตอนหน้าครับ\n","permalink":"https://yothinix-com.pages.dev/dvorak/","summary":"\u003cp\u003eใน \u003ca href=\"/ergodox-ez-dvorak-layout-ep-1-ergodox-ez\"\u003eตอนที่แล้ว\u003c/a\u003e เราพูดถึงคีย์บอร์ด Ergodox EZ ไปแล้ว ในตอนนี้ผมจะมาพูดถึงตัว \u003ca href=\"https://en.wikipedia.org/wiki/Dvorak_keyboard_layout\"\u003eDvorak Keyboard Layout\u003c/a\u003e บ้างในตอนนี้ว่าทำไม ผมถึงเลือกใช้ตัวนี้และผมเดาว่าหลายๆ คนน่าจะมีคำถามว่า เปลี่ยนแล้วพิมพ์เร็วขึ้นเหรอ เดี๋ยวผมจะมาตอบคำถามในตอนนี้นะครับ\u003c/p\u003e\n\u003ch2 id=\"dvorak\"\u003e\u003cstrong\u003eDvorak\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eก่อนอื่น ถ้าใครเคยสังเกตุคีย์บอร์ดที่เราใช้อยู่กันปกติ ถ้าเป็นแป้นภาษาอังกฤษจะอยู่บนพื้นฐานของ Layout ชื่อว่า \u003ca href=\"https://en.wikipedia.org/wiki/QWERTY\"\u003eQWERTY\u003c/a\u003e ครับ ซึ่งใช้มาตั้งแต่ยุคเป็นเครื่องพิมพ์ดีดมา ซึ่งลือกันว่าที่ Layout ถูกวางแบบนี้เพื่อที่จะให้แป้นพิมพ์ขัดกันน้อยที่สุดในยุคนั้นครับ แต่จริงๆ เรื่องนี้มีอะไรมากกว่านั้นครับ ถ้าลอง Search ดูจะสนุกมาก แต่ไม่ใช่ประเด็นหลักที่ผมจะมาเล่าวันนี้\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/dvorak/tlc_vBIm2w_hu_cda0225f7ae271f7.webp\"\n       srcset=\"/dvorak/tlc_vBIm2w_hu_cda0225f7ae271f7.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"222\"\n       alt=\"Dvorak-heatmap.jpeg\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eDvorak Heat map จาก \u003ca href=\"https://www.daskeyboard.com/blog/the-dvorak-keyboard-layout/\"\u003edaskeyboard.com/blog/the-dvorak-keyboard-la..\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eข้ามเรื่อง QWERTY มาจนปี 1932 August Dvorak ได้เปิดตัว Dvorak Simplified Keyboard โดยออกแบบมาเพื่อลดความผิดพลาด, เพิ่มความเร็วและลดความเมื่อยล้าที่เกิดจากการพิมพ์ครับ โดยศึกษาจากความถี่ของตัวอักษรที่ถูกพิมพ์ในภาษาอังกฤษ ฟีเจอร์หลักๆ จะมี\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eนำเอาตัวอักษรที่พิมพ์บ่อยที่สุดมาไว้ใน home row ทำให้เรา ไม่ต้องขยับนิ้วขึ้นลงบ่อยๆ เหมือน QWERTY\u003c/li\u003e\n\u003cli\u003eตัวสระในภาษาอังกฤษทั้งหมดก็อยู่ใน home row ด้วยครับ\u003c/li\u003e\n\u003cli\u003eตัวอักษรที่พิมพ์บ่อยๆ Dvorak จะย้ายมันไปอยู่ top row แทน bottom row ครับ เพราะเชื่อว่า เราสามารถยกนิ้วขึ้นไปพิมพ์ได้ง่ายกว่ากดนิ้วลงมาใน bottom row\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eโดยอัตราส่วนในการพิมพ์ของแต่ละ row (top-home-bottom) ของ Dvorak จะอยู่ที่ 22% - 70% - 8% เทียบกับ QWERTY ซึ่งอยู่ที่ 52% - 32% - 16%\u003c/p\u003e","title":"แชร์ประสบการณ์ปรับมาใช้ Ergodox และ Dvorak ในหนึ่งเดือน EP 2: Dvorak Keyboard Layout"},{"content":"ช่วงที่ผ่านมาหลายๆ คนน่าจะ WFH มากขึ้นใช่มั้ยครับ และผมเชื่อว่าหลายๆ คนน่าจะรู้สึกเหมือนผมว่า พอเรา WFH เราเริ่มจะอยู่กับคอมนานมากขึ้นไปอีกถ้าเราเป็น Programmer เพราะเราไม่ต้องเสียเวลาเดินทาง หรือออกไปซื้อข้าวเหมือนแต่ก่อน แล้วพอเราใช้เวลาอยู่หน้าคอมมากขึ้น เราก็จะเริ่มรู้สึกปวดเมื่อยล้าขึ้นตามมาในจุดต่างๆ ไม่ว่าจะเป็นที่คลาสสิกอย่าง คอ บ่า ไหล่ หรือจะเป็นข้อมือ หรือนิ้ว\nส่วนตัวผมก็ประสบกับปัญหาพวกนี้ไม่ต่างกันครับ และหนึ่งในวิธีที่ผมใช้มาแก้ปัญหานี้คือ การเปลี่ยนมาใช้ Ergonomic keyboard อย่าง Ergodox EZ ครับ แต่ก่อนจะไปถึงจุดนั้น ผมอยากจะแนะนำให้ทุกคนรู้จักกับ Split keyboard และ Ortholinear layout ก่อนครับ\nอะไรคือ Split keyboard Split keyboard เป็นคีย์บอร์ดอีกประเภทนึงที่จัดอยู่ในแนว Ergonomic keyboard โดยจุดเด่นหลักๆ อยู่ที่ตัวแป้นคีย์บอร์ดจะโดนหั่นครึ่ง ออกมาแยกออกจากกัน ซึ่งมีทั้งแบบ split ที่แยกออกจากกันไปเลยเป็น 2 ชิ้นแล้วเชื่อมกันผ่านสายเช่น Ergodox, Matias Ergo Pro, Kinesis Freestyle ฯลฯ หรือแบบ unibody ที่ยังอยู่ในเคสเดียวกันแต่ถูกจัดวางให้เอียงออกมารับสรีระมากกว่าปกติเช่น Microsoft Sculpt Ergonomic, Kinesis Advantage 2\nส่วนประเภท split ที่แยกออกจากกันเป็น 2 ชิ้นเราสามารถจะจัดตัวคีย์บอร์ดให้วางรองรับมือและแขนให้รองรับ natural posture ให้มากที่สุด ใครหน้าอกกว้าง หรือมุมแขนเป็นยังไง สามารถจัดได้อย่างอิสระเลยครับ โดยคำแนะนำของเค้าคือ ให้เรายื่นแขนออกไปตรงๆ แล้วลองวางมือดูก็จะได้จุดที่สบายที่สุดครับ\nแล้ว Ortholinear หละคืออัลไล ถ้าเราลองก้มลงไปดูคีย์บอร์ดปกติที่เราใช้อยู่ในทุกๆ วัน เราจะเห็นว่าตัวแป้นมันจะมีความเอียงๆ ไปทางซ้ายหน่อยๆ แล้วถ้าเราลองวางมือในแป้นเหย้า​ (home row) เราจะเห็นว่ามือเรามันเอียงไปทางซ้ายจริงๆ และบางปุ่มจะต้องเอื้อมนิ้วหนักมากเช่นเลข 6 ที่ควรจะถูกกดด้วยนิ้วชี้ข้างขวาจะเอื้อมไกลมากๆ ถ้าเทียบกับเลข 5 ที่ยื่นขึ้นไปนิดเดียว\nOrtholinear เกิดมาเพื่อแก้ปัญหานี้ครับ โดยทุกๆ ปุ่มจะถูกวางเรียงเท่าๆ กันในทุกๆ ปุ่ม ทำให้ระยะห่างของปุ่มต่างๆ มันเท่ากันทั้งคีย์บอร์ดครับไม่ว่าจะพิมพ์จากมือซ้าย หรือมือขวา ทำให้ระยะที่เราเอื้อมนิ้วโดยเฉลี่ยมันน้อยลงด้วยถ้าเทียบกับ layout ปกติครับ โดย Ortholinear ที่ดังที่สุดหนีไม่พ้น Planck keyboard ครับที่เป็นคีย์บอร์ด 47 ปุ่มเรียงกันเป็นตาราง Ortholinear ซึ่งถึงแม้ว่าจะมีปุ่มแค่นี้ แต่การใช้งานคีย์บอร์ดประเภทนี้เราจะเริ่มใช้ปุ่มต่างๆ ที่ขาดไปจากคีย์บอร์ดปกติผ่านระบบ layer ครับ ซึ่งเป็นเรื่องปกติของคนที่ใช้ custom keyboard เลย\nรู้จักกับ Ergodox EZ ต้องบอกว่าครั้งแรกที่ผมมองหา Split Keyboard ผมไม่ได้มองมาที่ Ergodox EZ ครับ แต่มองไปที่ Sol 3 จาก RGBKB ครับ ซึ่งจุดเด่นของมันคือ ความ custom ได้นี่แหละทุกชิ้นส่วนตั้งแต่ case เรื่อยมาจน touch bar module เราสามารถเลือกได้หมดเลย แต่ระหว่างที่ผมกำลังหาข้อมูล ผมตระหนักอย่างนึงว่า ไหนๆ ต้อง custom ขนาดนี้น่าจะต้อง flash firmware custom ตัว layout บ่อยมากแน่ๆ แล้วผมมีประสบการณ์ไม่ค่อยดีกับ QMK เท่าไร เลยหันมามอง Ergodox EZ แทนครับ\nErgodox EZ พัฒนาต่อยอดมาจาก Ergodox อีกที ซึ่งทุกอย่างเป็น open source เราสามารถใช้ 3D printer, print PCB ฯลฯ สร้างขึ้นมาเองได้ครับ แต่ Ergodox EZ ช่วยทำให้ชีวิตเราง่ายกว่านั้นครับ โดยเราสามารถเลือกแต่ละ component ขึ้นมาได้ผ่าน website เลยเพื่อ pre-build Ergodox EZ ให้ตรงกับที่เราต้องการมากที่สุดครับ\nโดยที่เซตที่ผมเลือก เป็นสีขาว มี Tilt Kit, Wing Rest ไม่มีไฟลอดใต้ปุ่ม (shine) และไม่มีไฟใต้คีย์บอร์ด (Glow) ครับ ในส่วนของคีย์แคปผมเลือกเป็น Blank sculpted keycaps เพราะว่ากะจะเปลี่ยน Layout อยู่แล้วเลยไม่คิดว่า printed QWERTY keycap จำเป็น และเลือก Switch เป็น Cherry MX Silent Red เพราะว่าช่วงหลังๆ ต้อง WFH แบบเปิดลำโพงฟัง discord บ่อยๆ เลยอยากได้ switch เงียบๆ เอาไว้ทำงานซึ่ง option ที่ผมเลือกก็ลดราคาของ Ergodox EZ ไปได้ระดับนึง แต่ก็ยังราคาพอๆ กับ Custom Tofu60 กับ Switch ดีๆ เลย\nOryx Configurator \u0026amp; Wally EZ Flash Tool ก่อนหน้านี้ผมบอกว่า ผมมีประสบการณ์ไม่ดีกับ QMK เพราะผมรู้สึกว่าหน้าเว็บในการใช้งานมันจะงงๆ หน่อย จนผม Flash firmware keyboard พังคามือมาแล้ว ด้วย pain ตรงนี้เลยเป็นเหตุผลหลักที่ผมเลือก Ergodox EZ เพราะชุด Software ของมันเลย\nในส่วนของ Software จะแบ่งเป็น 2 ส่วนคือ Oryx Configurator ซึ่งเป็นหน้าเว็บที่เราจะเข้ามาทำการ config ปุ่มต่างๆ ใน Ergodox ให้มันทำงานได้ในแบบที่เราต้องการ ซึ่งรองรับการ config ได้มากที่สุดถึง 32 layer เลยทีเดียว แต่ฟีเจอร์ที่ผมใช้บ่อยๆ นอกจากตั้งปุ่มตาม Layout พิเศษของตัวเองคือ dual function key ที่กดแช่จะเป็นคีย์นึง แต่ถ้า tap จะเป็นอีกคีย์ หรือพวก combo/macro modifier ที่ช่วยให้เรา custom ปุ่มๆ นึงให้ทำงานในแบบที่เราต้องการได้เลย ซึ่งเรื่องนี้เดี๋ยวผมมาลงรายละเอียดอีกทีในตอนต่อๆ ไป ครับว่าผมทำอะไรกับมันไปบ้าง แต่บอกได้เลยว่า นี่คือ hightlight ของการเปลี่ยนแปลงครั้งนี้เลย\nอีกส่วนของ Software คือ Wally ครับ ซึ่งเป็น Firmware Flashing tool ซึ่งมันใช้ง่ายมากๆ คือ พอเราได้ layout ที่ compile มาจาก Oryx แล้วจะได้ไฟล์ hex มาไฟล์นึง ที่เหลือเราก็แค่ลากไฟล์นั้นใส่ Wally แล้วเอาคลิปหนีบกระดาษจิ้มปุ่ม reset ทีนึง Wally ก็จะ Flash firmware ให้ใหม่จนจบก็ใช้งานได้เลย ไม่ต้องถอด usb ของคีย์บอร์ดเสียบใหม่ด้วย ง่ายมั้ยหละครับ\nTilt-Kit \u0026amp; Wing Rest ส่วนตัวผมเป็นคนใช้คีย์บอร์ดแบบไม่เคยมีที่รองมือมาตลอด ซึ่งมันก็จะมีความเกร็งๆ ข้อมือให้งอขึ้นอีก แทนที่จะอยู่ใน Position ที่งอลงปกติ พอมี Wing Rest ของ Ergodox นอกจากจะรู้สึกว่าม้ือวางงอลงแล้วมันเกร็งข้อน้อยลงแล้ว อีกส่ิงหนึ่งที่ผมรู้สึกได้ชัดคือ ข้อมือมันล็อกมากขึ้นครับ คือในหลายๆ ครั้งแต่ก่อน ผมซึ่งพิมพ์ภาษาอังกฤษบนคีย์บอร์ดแบบไม่ถูกหลักมือมันจะลอยไปลอยมาไม่ค่อยอยู่กับฐาน จะอาศัย home row เป็นตัวกะระยะก่อนที่จะเอื้อมไปกด แต่พอมีที่รองข้อมือ รู้สึกว่ามือเรามันกลับฐานมาในแบบที่ควรจะเป็นบ่อย แล้วก็ไม่ค่อยเมื่อยแขนละ เพราะมือไม่ค่อยลอยรอกดปุ่มละ\nส่วน Tilt-Kit นี่ถ้าเราสังเกตุดีๆ คีย์บอร์ดปกติ เราจะบิดข้อมือเล็กน้อย (นอกจากเอียงซ้ายแบบ layout ปกติ) เพื่อให้ม้ือเราวางแบนราบเหนือแป้นพอดี ซึ่งพอเราทำงานไปนานๆ นี่เป็นสาเหตุว่าทำไมแถวๆ ข้อแขนมันเมื่อยด้วยนอกจากข้อมือเราที่บิดอยู่แล้ว ตัว Tilt-Kit เลยออกมาแก้ปัญหานี้ครับ โดยอาศัยข้อได้เปรียบที่คีย์บอร์ดเราแยกร่างแล้ว แล้วทำไมเราจะทำให้มัน support มือเรามากกว่าเดิมหละ โดย Position ที่คนนิยมกันคือ ดัน Tilt-Kit ข้างในยกให้สูงที่สุดครับ มันทำให้คีย์บอร์ดยกมารับกับมือมากขึ้น ใกล้เคียงกับ Natural Position คล้ายๆ เวลาเราถือดาบหรือกำด้ามปืนครับ\nในส่วนนี้ตอนแรกๆ ผมก็รู้สึกว่ามันสบายมากขึ้นแล้วนะแค่ Tilt-Kit อย่างเดียว แต่พอไปดูหลายๆ ที่เค้าจะเอาอะไรมาวางเสริมขึ้นไปอีกเพื่อให้องศาที่คีย์บอร์ดยกมารองรับมือเราสูงขึ้น โดยตอนนี้ผมจบที่เอาสมุด Moleskine เล่มเก่าๆ มาวางซ้อนๆ กันแล้ววางขา Tilt-Kit ข้างในบนนั้นมุมอยู่ที่ประมาณ 20 องศา ก็สบายแล้วครับ แต่ผมเห็นบางคนเอียงไปไกลกว่านั้น ก็แล้วแต่พื้นที่แต่ละคนเลย\nพูดถึงข้อดีมาเยอะ พูดถึงข้อเสียบ้างละกัน อย่างแรกคือ ตัว Interface ของสายยังเป็น Mini USB อยู่ครับ ซึ่งคีย์บอร์ดสมัยนี้แทบจะไม่ใช้กันแล้ว ทำให้การจะหา custom cable มันก็จะคิดหนักหน่อย ซึ่งจนถึงปัจจุบันที่ผมใช้มาหนึ่งเดือนก็ยังใช้สายเดิมๆ ที่แถมมากับคีย์บอร์ดอยู่ (ซึ่งยาวมาก)\nข้อเสียต่อมายังคงเป็นเรื่องสายครับ เพราะว่า Interface เชื่อมระหว่างคีย์บอร์ดเป็นหัว TRRS 4 Core ซึ่ง ถ้าพูดง่ายๆ มันคือสาย AUX หูฟังครับ แต่ด้วยความที่มันเป็น 4 core 2 ข้างเลย มันหายาก (แต่ไม่ใช่ว่าหาไม่ได้นะ) เพราะส่วนใหญ่ที่เจอจะเป็น ปลายข้างนึง 4 core อีกข้าง 3 core ซึ่งผมเข้าใจว่ามันไม่ compatible กันครับ นี่ยังไม่นับว่าสายมันยาวมากด้วยนะ ทำให้เกะกะโต๊ะมากครับ\nต่อมาเป็นเรื่องขนาดคีย์บอร์ดครับ ถึงแม้จะเป็น Ortholinear แล้ว Tilt แล้ว แต่ผมยอมรับว่าหลายๆ ปุ่มผมก็ยังกดไม่ถึงครับยกตัวอย่างเช่นปุ่มเล็กๆ แถวๆ Thumb cluster ผมเอื้อมสุดมือก็ยังไม่ถึง ต้องยกมือขึ้นมากดถึงจะได้ หรืออย่างพวกปุ่มใต้อุ้งมือในแถวล่างสุด 3 ตัวซ้าย/ขวาสุด ช่วงแรกๆ ผมพยายามใช้แต่มันฝืนธรรมชาติจริงๆ สุดท้ายผมก็เลิกใช้มันไปครับ\nข้อเสียสุดท้ายที่ผมนึกออกตอนนี้คือ Keycaps ครับ ถ้าเป็นสาย custom สะสม keycaps การเปลี่ยนมาใช้ Ergodox จะทำให้ชีวิตเรายากขึ้นไปอีก การหา keycaps ที่รองรับ Ergodox จะยากขึ้นไปอีกเท่าตัว เพราะปัญหาหลักๆ คือปุ่ม 2u ที่อยู่ข้างๆ กับพวก Thumb cluster ครับ เรียกได้ว่าถ้า GB ออกมาแล้วบอกว่ามีรองรับ Ergodox นี่ต้องรีบคิดให้ไวเลย และนี่เป็นเหตุผลหลักที่ผมเลือก Ergodox แทน Moonlander เลยเพราะว่าถึงแม้จะยาก แต่ยังมีแต่ Moonlander นี่ไม่มีเลย แต่ถ้ามองอีกมุมคือ เราก็ประหยัดตังค์ค่า keycaps ไปได้เยอะมาก เพราะมันไม่ค่อยมีให้เลือกนี่แหละ\n———————\nสำหรับตอนแรกก็น่าจะพอแค่นี้ก่อนครับ ในตอนถัดไปเดี๋ยวผมจะมาพูดถึง Dvorak Keyboard Layout ที่ผมเลือกมาใช้คู่กับ Ergodox ตัวนี้ ก็คอยติดตามต่อกันได้ครับ ถ้าใครชอบบทความสามารถกด subscribe ได้ในช่องข้างล่างเลยครับ หรือจะกดไลค์เพจ เขียนงูให้วัวกลัว ก็ได้ แล้วเจอกันใหม่ตอนหน้าครับ\n","permalink":"https://yothinix-com.pages.dev/ergodox-ez/","summary":"\u003cp\u003eช่วงที่ผ่านมาหลายๆ คนน่าจะ WFH มากขึ้นใช่มั้ยครับ และผมเชื่อว่าหลายๆ คนน่าจะรู้สึกเหมือนผมว่า พอเรา WFH เราเริ่มจะอยู่กับคอมนานมากขึ้นไปอีกถ้าเราเป็น Programmer เพราะเราไม่ต้องเสียเวลาเดินทาง หรือออกไปซื้อข้าวเหมือนแต่ก่อน แล้วพอเราใช้เวลาอยู่หน้าคอมมากขึ้น เราก็จะเริ่มรู้สึกปวดเมื่อยล้าขึ้นตามมาในจุดต่างๆ ไม่ว่าจะเป็นที่คลาสสิกอย่าง คอ บ่า ไหล่ หรือจะเป็นข้อมือ หรือนิ้ว\u003c/p\u003e\n\u003cp\u003eส่วนตัวผมก็ประสบกับปัญหาพวกนี้ไม่ต่างกันครับ และหนึ่งในวิธีที่ผมใช้มาแก้ปัญหานี้คือ การเปลี่ยนมาใช้ Ergonomic keyboard อย่าง \u003ca href=\"https://ergodox-ez.com/\"\u003eErgodox EZ\u003c/a\u003e ครับ แต่ก่อนจะไปถึงจุดนั้น ผมอยากจะแนะนำให้ทุกคนรู้จักกับ Split keyboard และ Ortholinear layout ก่อนครับ\u003c/p\u003e\n\u003ch2 id=\"อะไรคอ-split-keyboard\"\u003e\u003cstrong\u003eอะไรคือ Split keyboard\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eSplit keyboard เป็นคีย์บอร์ดอีกประเภทนึงที่จัดอยู่ในแนว Ergonomic keyboard โดยจุดเด่นหลักๆ อยู่ที่ตัวแป้นคีย์บอร์ดจะโดนหั่นครึ่ง ออกมาแยกออกจากกัน ซึ่งมีทั้งแบบ split ที่แยกออกจากกันไปเลยเป็น 2 ชิ้นแล้วเชื่อมกันผ่านสายเช่น Ergodox, Matias Ergo Pro, Kinesis Freestyle ฯลฯ หรือแบบ unibody ที่ยังอยู่ในเคสเดียวกันแต่ถูกจัดวางให้เอียงออกมารับสรีระมากกว่าปกติเช่น Microsoft Sculpt Ergonomic, Kinesis Advantage 2\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/ergodox-ez/H-j4EbRKQ_hu_3501d3bee7a49348.webp\"\n       srcset=\"/ergodox-ez/H-j4EbRKQ_hu_3501d3bee7a49348.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"226\"\n       alt=\"818T–WBwvL.AC_.jpg\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e","title":"แชร์ประสบการณ์ปรับมาใช้ Ergodox EZ และ Dvorak layout ในหนึ่งเดือน EP 1: Ergodox EZ"},{"content":"ตั้งแต่จำความได้แล้วบอกที่บ้านว่าโตขึ้นจะเป็น Programmer เขียนโปรแกรม​ ฯลฯ จะต้องเจอคำพูดประมาณว่า อ่อคอมพิวเตอร์มันก็มีแค่ 0 กับ 1 เท่านั้นแหละ พอโตขึ้นมาอีกหน่อยตอนอยู่มัธยมก็เริ่มรู้จักตรรกศาสตร์​ซึ่งเป็นพื้นฐานของ Boolean Algebra แล้วก็พอรู้ว่า อ่อเดี๋ยวไปเขียนโปรแกรมน่าจะได้ใช้เยอะ (ตอนนั้นยังไม่รู้จัก Demorgan\u0026rsquo;s law) พอเข้ามหาลัยหน่อยได้เรียนวิชา Digital ก็รู้สึกว่าใกล้ละเริ่มเห็น OP AMP เห็น Microcontroller, Microprocessor แล้วก็ข้ามไปวิชา OS เลย ทิ้งช่องว่างระหว่าง Hardware กับ Software ไว้ในใจโยธินมาเป็นระยะเวลาหลายปี\nจนกระทั่งปีนี้เรียกว่าจับพลัดจับพลูมารู้จักคอร์ส nand2tetris จากพี่อรรถ จากบทสนทนาตอนเย็นในที่ทำงานที่คุยกันไปเรื่อยในหัวข้อการเขียนโปรแกรม ประกอบกับในช่วงนี้ของชีวิตรู้สึกโหยหาอะไรที่มัน Fundamental, Foundation, Theoretical มากเลยตั้งปณิธานไว้ว่า สงกรานต์นี้เราจะเรียนคอร์สนี้\nต้องเกริ่นก่อนว่าคอร์ส Build a Modern Computer from First Principles: From Nand to Tetris (Project-Centered Course) นี่เป็นหนึ่งในคอร์สระดับตำนานของ Coursera เลยครับ ที่มีคนเรียนมากกว่าแสนคน และได้รับคะแนนรีวิวถึง 4.9 คะแนนเต็ม 5 โดยคนสอนเป็น Professor จาก the Hebrew University of Jerusalem สองคนคืออาจารย์ Shimon Schocken และอาจารย์ Noam Nisan ครับ โดยใช้เวลา 6 สัปดาห์ในการสร้าง Hack Computer ขึ้นมา ตั้งแต่ระดับเบสิกที่สุดคือ NAND gate ไปจนถึงมีสถาปัตยกรรมคอมพิวเตอร์จริงๆ\nผมจำได้แม่นเลยว่าชั่วโมงแรกๆ ที่เรียนผมยังไม่อินมากเพราะ Logic Gate เป็นอะไรที่เคยเรียนมาแล้วตอนมหาลัย แต่ความสนุกของคลาสนี้มันอยู่ที่ Assignment ครับที่ถูกออกแบบมาดีมากๆ โดยเราเริ่มจาก NAND gate ซึ่งเป็น Logic gate พื้นฐานที่สุด แล้วค่อยๆ ประกอบร่างมันขึ้นมาเป็น And, Or, Xor, Mux, DMux เริ่มขยาย input จาก 2 เป็น 4, 8 และ 16 จนถึงจุด Mux4Way16 นี่คือมัน Challenge จริงๆ จนต้องนอนหนึ่งคืนก่อนจะคิดออกในเช้าวันต่อมาว่า อ่อมันน่าจะประมาณนี้\nสิ่งที่ต้องชมอีกอย่างนอกจาก Assignment คือ Tooling และ Course Material ซึ่งเตรียมมาดีมากโดยเฉพาะ Hardware Simulator ที่ทำให้เราเขียนโปรแกรมจำลอง hardware ขึ้นมาเรื่อยๆ เพราะนี่มัน Computer Science เราแค่ Design Hardware ผ่าน HDL ก็พอส่วนการประกอบวงจรจริงๆ ฯลฯ เป็นปัญหาของ Electrical Engineering ไป\nนอกจากนั้นในแต่ละ Assignment จะมี Test program ที่เราสามารถรันผ่าน Hardware simulator ต่างๆ ได้ซึ่งไม่ได้มีแค่ test file เดียวแต่จะไล่ระดับ ทำให้เรารู้ว่าพลาดตรงไหนใน Implementation ของเราด้วย ทำให้การทำโจทย์แต่ละสัปดาห์เป็น Test Driven Development ที่แท้จริง\nรูปแบบของการเรียนจะค่อยๆ ต่อยอดความรู้ของเราในแต่ละสัปดาห์ขึ้นมาเป็น Hardware abstraction ที่ซับซ้อนขึ้นเรื่อยๆ โดยในสัปดาห์ที่สองจะเอาพวก Logic Gate พื้นฐานที่เราสร้างกันมาประกอบร่างกันเป็น Adder, จนไปถึง ALU ซึ่งสนุกมาก เพราะการ compose ความรู้มาเป็น logic gate ที่ทำงานร่วมกันได้นี่ได้ใช้เทคนิคอย่าง Divide and conquer มาช่วยแก้ปัญหาเพราะ ALU มี input, output หลาย combination มาก แต่เราก็เริ่มจะเห็นภาพแล้วว่า อ่อ ถ้า input มันเข้ามาประมาณนี้ มันจะออกมาประมาณนี้แหละ เรียกว่าใกล้เคียงระดับการโปรแกรมมากขึ้นไปอีกขั้น\nในสัปดาห์ที่ 3 เราไปทำความรู้จักกับหน่วยความจำซึ่งนอกจากรู้ว่า RAM, ROM ต่างกันยังไง ผมไม่เคยรู้อะไรข้างในชิปดำๆ มาก่อนเลย ผมจำได้แม่นเลยว่าผมประทับใจความสวยงามของ Memory มาก ซึ่งเริ่มจากพื้นฐานง่ายๆ อย่าง Flip-Flop รวมร่างเป็น Register แล้วกลายเป็น Ram ที่ค่อยๆ ยก Abstraction รูปแบบเดิมๆ ขึ้นมาด้วยขนาดที่ใหญ่ขึ้นเรื่อยๆ จนมาถึง Program Counter\nvia GIPHY\nส่วนสัปดาห์ที่ 4 ค่อนข้างจะกระโดดข้ามการไต่ระดับเรามาไกลหน่อย เพื่อให้เราเห็นภาพของ Machine Language Programming ซึ่งส่วนตัวผมไม่เคยเขียน Assembly มาก่อนแล้วต้องมาจัดการ Memory Register แต่ละ address เอง แล้วมี operation ให้ใช้จำกัดจำเขี่ยมาก แต่ก็สามารถเขียนโปรแกรมมี Loop มีการ control pixel ในหน้าจอของ Hardware simulator ได้มันภูมิใจมากนะ\nสัปดาห์ที่ 5 เป็นสัปดาห์ที่ใจฟูมากสำหรับผม เพราะว่านับตั้งแต่เริ่มประกอบ NAND gate มาในสัปดาห์แรกจนผ่านมาหนึ่งเดือน นี่เป็นสัปดาห์ที่เราจะประกอบทุกอย่างเข้าด้วยกันจริงๆ ซึ่งสำหรับผมตอนประกอบ Computer.hdl ท้ายสุดผมไม่ดีใจเท่าตอนประกอบ CPU.hdl ได้ ซึ่งเราได้เห็นจริงๆ ว่าสถาปัตยกรรมที่เราสร้างมันขึ้นมามันทำงานได้จริงๆ\nในสัปดาห์สุดท้ายของคอร์สพาเราไปรู้จักกับ Assembler ซึ่งเชื่อม Gap ระหว่างสัปดาห์ที่ 4 ที่เป็น Machine Language กับ Computer Architecture ในสัปดาห์ที่ 5 เข้าด้วยกัน โดยโจทย์ของสัปดาห์นี้คือให้สร้าง Assembler โดยใช้ภาษาอะไรก็ได้ที่เราถนัด มา compile Assembly program ให้กลายเป็น machine code 01 ที่ CPU เอาไปทำงานได้ ซึ่งผมสนุกมากและภูมิใจมากในวินาทีที่เรารันโปรแกรมเทสสุดท้ายผ่านจริงๆ\nต้องบอกว่าหลังเรียนคอร์สนี้จบ Gap ที่ผมไม่เคยเข้าใจว่า Computer ในระดับ Hardware มันทำงานยังไงได้รับการคำตอบจากคอร์สนี้จริงๆ ครับ และผมยินดีจะแนะนำต่อให้กับทุกคนที่ทำงานในสาย IT เลยว่าควรหาโอกาสมาเรียนคอร์สนี้ซักครั้ง เพราะมันดีมากจริงๆ\nสุดท้ายครับ ผมอยากบอกว่านี่เพิ่งครึ่งทางของคอร์สนี้เท่านั้น เพราะคอร์สนี้จริงๆ มี 2 Part ครับ ซึ่งจริงๆ เราจะรู้ตั้งแต่วันแรกที่เรียนละ แต่ว่าพอดำไปเดือนนึง ผมลืมตรงนี้ไปเลย โดยคอร์ส Part 2 ที่ผมรู้คร่าวๆ คือจะเน้นไปทาง Software architecture ละตั้งแต่ VM, compiler ไปจนถึง OS เลย ซึ่งผมไม่พลาดที่จะเรียนต่อแน่ๆ เพราะมาได้ครึ่งทางละ และคงได้มีโอกาสมารีวิวอีกรอบครับถ้าจบแล้ว\nส่วนใครที่อ่านมาถึงตรงนี้แล้วคิดว่าผมยัง Convince ไม่พอผมแนะนำให้ดู TED Talk นี้ครับ เพราะอาจารย์ Shimon Schocken นี่เค้ามี Passion จริงๆ จนกว่าจะมาเป็นคอร์สนี้ได้คือสุดมาก ฟังแล้วจะมีไฟอยากเรียนรู้อะไรๆ เพิ่มขึ้นไปอีกเลยครับ 🔥🔥🔥🔥🔥\nปล. เป็นหนึ่งใน Cert ที่เรียนจบแล้วชอบมาก จบจริงๆ นะไม่ได้โม้\n","permalink":"https://yothinix-com.pages.dev/nand2tetris/","summary":"\u003cp\u003eตั้งแต่จำความได้แล้วบอกที่บ้านว่าโตขึ้นจะเป็น Programmer เขียนโปรแกรม​ ฯลฯ จะต้องเจอคำพูดประมาณว่า อ่อคอมพิวเตอร์มันก็มีแค่ 0 กับ 1 เท่านั้นแหละ พอโตขึ้นมาอีกหน่อยตอนอยู่มัธยมก็เริ่มรู้จักตรรกศาสตร์​ซึ่งเป็นพื้นฐานของ Boolean Algebra แล้วก็พอรู้ว่า อ่อเดี๋ยวไปเขียนโปรแกรมน่าจะได้ใช้เยอะ (ตอนนั้นยังไม่รู้จัก Demorgan\u0026rsquo;s law) พอเข้ามหาลัยหน่อยได้เรียนวิชา Digital ก็รู้สึกว่าใกล้ละเริ่มเห็น OP AMP เห็น Microcontroller, Microprocessor แล้วก็ข้ามไปวิชา OS เลย ทิ้งช่องว่างระหว่าง Hardware กับ Software ไว้ในใจโยธินมาเป็นระยะเวลาหลายปี\u003c/p\u003e\n\u003cp\u003eจนกระทั่งปีนี้เรียกว่าจับพลัดจับพลูมารู้จักคอร์ส \u003ca href=\"https://www.coursera.org/learn/build-a-computer\"\u003enand2tetris\u003c/a\u003e จากพี่อรรถ จากบทสนทนาตอนเย็นในที่ทำงานที่คุยกันไปเรื่อยในหัวข้อการเขียนโปรแกรม ประกอบกับในช่วงนี้ของชีวิตรู้สึกโหยหาอะไรที่มัน Fundamental, Foundation, Theoretical มากเลยตั้งปณิธานไว้ว่า สงกรานต์นี้เราจะเรียนคอร์สนี้\u003c/p\u003e\n\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/wTl5wRDT0CU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cp\u003eต้องเกริ่นก่อนว่าคอร์ส \u003ca href=\"https://www.coursera.org/learn/build-a-computer\"\u003eBuild a Modern Computer from First Principles: From Nand to Tetris (Project-Centered Course)\u003c/a\u003e นี่เป็นหนึ่งในคอร์สระดับตำนานของ Coursera เลยครับ ที่มีคนเรียนมากกว่าแสนคน และได้รับคะแนนรีวิวถึง 4.9 คะแนนเต็ม 5 โดยคนสอนเป็น Professor จาก the Hebrew University of Jerusalem สองคนคืออาจารย์ Shimon Schocken และอาจารย์ Noam Nisan ครับ โดยใช้เวลา 6 สัปดาห์ในการสร้าง Hack Computer ขึ้นมา ตั้งแต่ระดับเบสิกที่สุดคือ NAND gate ไปจนถึงมีสถาปัตยกรรมคอมพิวเตอร์จริงๆ\u003c/p\u003e","title":"Review Nand2Tetris (Part 1) คอร์สที่คน IT ควรจะเรียนสักครั้งในชีวิต"},{"content":"หลายปีที่แล้วผมเคยพูดไว้ว่า หนึ่งในสิ่งที่ผมชอบเกี่ยวกับภาษา Python ที่สุดคือ Community ครับ และผ่านมาหลายปี ผมก็ยังยืนยันคำเดิมว่า Python Community เป็นหนึ่งใน Tech community ที่เปิดรับและเป็นมิตรมากที่สุดที่หนึ่งครับ และงานใหญ่ที่สุดประจำปีของชาว Python คืองาน PyCon US หรือหลาย ครั้งก็เรียกกันแค่ PyCon เพราะที่นี่เป็น Original ก่อนจะมี regional PyCon ต่าง ไม่ว่าจะเป็น Euro Python, PyCon AU, PyCon APAC หรือ PyCon Thailand ครับ\nและอย่างที่เรารู้กันดีว่าปี 2021 นี้ยังเป็นอีกปีที่การระบาดของไวรัส COVID-19 ทำให้นี่เป็นปีที่สองที่ PyCon US จัด Online ครับ ซึ่งข้อดีคือ ทำให้เราๆ ที่ไม่ได้อยู่ US สามารถร่วม Conference ได้เพียงแค่มี Computer / Internet เท่านั้นครับ แต่ข้อเสียคือ Timezone จะลำบากหน่อย เพราะเวลา US แทบจะกลับด้านกลางวันกลางคืนกับเวลาไทยเลย\nวิธีการ Scout หัวข้อผมก็ง่ายๆ ครับทำ Spreadsheet แล้วก็เรียงตาม timeline สำคัญคือ Track ไหนเวลาไหน\nการเตรียมตัว ก่อนจะถึง Conference หลังจากที่เรา Sign up ในเว็บไซต์ PyCon US (ซึ่งปรับใหม่แทบทุกปี) เราก็คอยติดตามข่าวดูได้ตลอดครับว่ามี Tutorial หรือ Talk อะไรบ้าง ซึ่งหัวข้อจะเยอะมาก และหลายๆ หัวข้อที่เราสนใจก็มักจะมาในเวลาเดียวกันแต่อยู่คนละ Track เพราะฉะนั้น ช่วงสัปดาห์ก่อนวันงานจะเป็นช่วงที่ผมวางแผนว่า อยากจะเข้าไปฟัง ไป Discuss ใน Talk ไหนบ้าง เพื่อที่พอถึงวันงานจะได้ไม่ต้องมาเลือกแบบรีบๆ ครับ\nซึ่งสิ่งสำคัญอย่างนึงที่ผมค้นพบเลยคือ วางแผนเรื่อง Timezone ดีๆ ครับ เพราะใน Official PyCon US website จะแสดงเวลาเป็น US หมด แล้วผมมาค้นพบอีกทีตอนวันงานว่า Talk ที่อยากฟังจะอยู่ตอนใกล้ๆ เช้าเวลาไทย อะไรแบบนี้ ทำให้พลาดไป\nนอกจากหัวข้อที่ผมเตรียมตัวแล้ว อีกสิ่งหนึ่งที่เตรียมคือเวลานอนครับ จากประสบการณ์ PyCon Belarus กับ PyCascade ในช่วงต้นปีที่ผ่านมา ผมไม่เคยอยู่ได้เกินครึ่งงาน เพราะว่าสลบก่อนจากผลของ Different Timezone ครับ\nหน้าเว็บของ Hubilio ครับ จะเห็นว่าจำลองส่วนต่างๆ ของ Conference มาไว้ตรงเมนูหมดเลย\nช่วง​ Conference Day พอถึงเวลาแต่ละ Talk จะมี Schedule มาแจ้งเตือนครับ\nConference Day Conference Day ของ PyCon US ปีนี้ตรงกับคืนวันศุกร์ที่ 14 ถึงเช้าวันเสาร์ที่ 15 และคืนวันเสาร์ที่ 15 ถึงเช้าวันอาทิตย์ที่ 16 ครับ ซึ่งวันศุกร์จะเหนื่อยๆ หน่อย เพราะไปทำงานมาทั้งวัน แล้วมาต่อ Conference ในตอนกลางคืน ซึ่งช่วงสัปดาห์ของ PyConUS จะเร่ิมด้วย Tutorial กับ Language Summit ก่อนครับ แต่ผม Sign up สอง event นั้นไม่ทันก็เลยไม่ได้ร่วม ครับโดย Platform ที่ PyCon US เลือกใช้คือ Hubilio ครับ โดยทีมจะส่ง link ในการเข้างานมาให้ตั้งแต่ช่วงต้นสัปดาห์ครับ\nซึ่งใน Platform Hubilio นี่ก็มีตัวเลือกให้เราเล่นหลากหลายมาก จำลองมาจากงาน Conference จริงๆ ครับ ไม่ว่าจะเป็น Lounge หรือ Sponsor Booth ที่เราสามารถไปเยี่ยมชมหน้าเพจที่ custom มาโดยเฉพาะของ Sponsor ครับ รวมถึงเข้าไป Say Hi หรือนัดเวลาคุยกับพนักงานจาก Sponsor Booth ได้ด้วยครับ เหมือนเราไปคุยกับคนที่บูธจริงๆ เลย\nนอกจากนั้นแล้วด้วยความที่ Talk จะถูก Pre-record มาก่อนทำให้เราสามารถดูย้อนหลังได้ด้วยครับ ซึ่งมี Sponsor Workshop ที่ผมอยากฟังมากคือ Blackfire: Debugging Performance in Python and Django applications ก็สามารถกดเข้าไปดูย้อนหลังได้ครับ\nKeynote: Imaging Rembrandt’s The Night Watch at 5um Resolution (717 GP) with Python — Robert Erdmann (@erdmann) เป็น Talk ที่มาเล่าถึง Operation Night Watch ครับ ซึ่งเป็นโปรเจ็คการฟื้นฟูภาพ The Night Watch ของ Rembrant ครับ ซึ่งใน Talk เล่าถึงเทคนิคในการฟื้นฟูภาพที่ทีมนี้ใช้กัน ที่ผมขอเรียกว่าจุดสูงสุดของสาขา Image Processing เลยครับ ตั้งแต่การใช้กล้อง Hasselblad 100MP ถ่ายแต่ละส่วนของภาพ หรือใช้ Laser Rangefinder ในการวัดมุมของผืนผ้าใบของภาพ เพื่อสร้าง 3D Map รวมไปถึงเทคนิคในการ Optimization ผ่าน Machine Learning ต่างๆ เรียกได้ว่าถ้าใครหาแรงบันดาลใจในการทำ Image Processing ผมแนะนำ Talk นี้เลยครับ\nGenerating buzz with realtime FM audio synthesis — Łukasz Langa (@llanga) Talk นี้พาผมเข้าไปโลกดนตรี synthesis ครับผ่านการเขียนโค้ดสร้าง sine wave จาก Python แล้วเริ่มทำ filter frequency modulate แล้วทำเป็นเสียงผ่าน MIDI interface ครับ ผมชอบ Talk นี้ตรงที่ใช้ Feature ของ Python ใหม่ๆ หลายอย่างเลยทั้ง @dataclasses, Type annotation ที่ไม่ต้อง import Typing แล้วหรือ Generator ที่เราใช้ๆ กันทั่วไปนี่แหละครับ ส่วนตัวผมไม่ค่อยมีความรู้เรื่องดนตรีเลยไม่ค่อยเข้าใจเท่าไรเรื่อง Pitch, note, Envelop function แต่คนที่สนใจเรื่องดนตรีผมว่าน่าจะชอบมากครับ\nWriting Good Documentation for Developers — Meredydd Luff ตอนแรกผมเข้าอีก Talk นึงเรื่อง NumPy API แล้วผมฟังแล้วไม่ค่อยเกท เลยเปลี่ยนมาเข้า Talk นี้แทน แล้วสนุกดีครับ คือใน Talk เค้ามองว่า Documentation is content marketing ของ Software เรา ซึ่งคนอื่น Care มั้ยไม่รู้ แต่เค้าแคร์เพราะเป็นการสร้างประสบการณ์ที่ดีให้กับคนที่มาใช้ Software เรา นอกจากนั้นการที่เค้ามอง Document usage ตามความเป็นจริงทั้ง zoom-in ที่ลงรายละเอียดขึ้นเรื่อยๆ จาก Tutorial, How-to เรื่อยไปจน API Docs หรือ Zoom-out ที่กลับด้านกัน ทำให้เราเข้าใจวิธีการเขียน journey ของการใช้งาน Document ได้ชัดมากครับ อีกจุดนึงที่ชอบของ Talk นี้คือวิธีการแบ่งประเภท Documents ตาม purpose ของมันจะช่วยให้เราโฟกัสกับการเขียนได้ดียิ่งขึ้นครับ และตอบโจทย์คนที่ใช้งานมากยิ่งขึ้น\nZero to production-ready best practice process for docker packaging — Itamar Turner-Trauring (@itamarst) หลายๆ คนน่าจะรู้จักเว็บไซต์ Python=\u0026gt;Speed กันใช่มั้ยครับ ที่ชอบพูดถึงเรื่อง Infrastructure เกี่ยวกับ Python โดย Talk นี้มาจากเจ้าของเดียวกันครับ ซึ่งพูดถึง Practices ที่เราควรทำเวลา Packaging Python docker แต่ด้วยความที่ Talk จำกัดเวลาแค่ 25 นาที ทำให้เค้าพูดถึงได้แค่บางส่วน ที่กลั่นมาแล้วว่าช่วยให้ชีวิตดีขึ้นแน่นอน เป็น Big Picture ที่เรียงตาม Priority มาให้แล้ว ส่วนตัวผมได้รู้เทคนิคใหม่สองเทคนิคคือ เราสามารถเปิด PYTHONFAULTHANDLER=1 เพื่อให้ CPython interpreter แสดง error ในชั้นที่ interface กับภาษา C ได้ครับ ซึ่งหลายๆ Library ใช้อยู่ไม่ว่าจะเป็น NumPy หรือ Matplotlib หรืออีกเทคนิคนึงคือ เราสามารถ Pre-compile pyc bytecode ได้ตั้งแต่ build Docker image ครับ ซึ่งช่วยลด start-up time ของ Docker Image เราได้ดีเลยทีเดียว\nRestarting Pyjion, a general-purpose JIT for Python — is it worth it? — Anthony Shaw (@anthonypjshaw) Talk นี้ผมไม่ได้ดูสดครับ เพราะหลับไปก่อน (ตี 4 เวลาไทยวันนั้น) แต่ข้อดีของ Online Conference คือ “เราสามารถมาดูย้อนหลังได้ครับ” ซึ่งผมก็มาดูย้อนหลังวันเสาร์ตอนกลางวัน แล้วน่าสนใจมากทีเดียว โดย Talk นี้เป็นการเพิ่มความเร็วในการทำงานของ Python ผ่าน Pyjion ซึ่งเป็น specialize JIT แทนตัวปกติที่มาจากภาษาครับ ซึ่ง JIT ตัวนี้จะช่วย optimize การทำงานบางส่วนของ CPython ให้เร็วขึ้นได้ เพียงแค่ pip install pyjion แล้ว import ไปใช้งานแค่นั้นเองครับ โดยรองรับ cross-platform ตั้งแต่ x86 — ARM เลย ซึ่งเทคนิคที่ Pyjion ใช้คือการ Profile โค้ดที่เคยรันแล้ว Optimize code ให้รันในรอบต่อๆ ไป ซึ่งเป็นเทคนิคคล้ายๆ กับ PyPy เลยครับเรียกว่า Profile Guided Compilation (PGC) ส่วนตัวอย่างใน Talk มีตั้งแต่ง่ายๆ อย่าง function เดี่ยวๆ ไปจนถึงการเอาไปใช้แก้ปัญหา n-body problem ซึ่งเร็วขึ้นถึง 33% เลยครับ\nผมจำได้ว่าผมเห็น Tweet นี้ของ @PyCon แล้วหลังจากนั้นผมจำอะไรไม่ได้อีกเลยของวันแรกครับ\nReminder that your body and health is important, if it\u0026#39;s getting a little late where you are, or you simply need a break, don\u0026#39;t fret!\nAll sessions are available for viewing at any time in the platform after they have been presented.\nTake time to hydrate, stretch, eat, or sleep.\n\u0026mdash; PyCon US (@pycon) May 14, 2021 Virtual Lighting Talks (May 15) ส่วนตัวผมพลาด Lighting talks วันแรกไปเพราะหลับไปก่อน แต่วันที่สองเป็น Session แรกเลย ได้เก็บมาครับ ซึ่งมีตั้งแต่ Promote Regional PyCon อย่าง PyCon Latam, PyCon Chile, หรืองานอย่าง Advent of Code เรื่อยไปถึงเทคนิคการใช้ Jupyter Notebook, pytest Parameterize tests หรือ f-string หรือ Promote Framework ที่ตัวเองทำอยู่ไม่ว่าจะเป็น\nCommitCanvas ที่ช่วยให้เรา commit เป็นรูปแบบที่เราตกลงกันในทีมผ่าน ML Model ที่เรียนรู้จาก Git commit history ของเรา APIFlask ซึ่งเป็น Framework ที่สมน้ำสมเนื้อกับ FastAPI มาก Direnv ช่วยให้เรา Config environment ตามโปรเจ็คแล้วอ่านตาม directory ในเครื่องเรา All-repos ช่วยให้เราทำงานกับ multi-repo git ได้ง่ายขึ้นผ่าน batch operation Keynote: Pythonization of Healthcare — Akshay Sharma Talk นี้พูดถึง Healthcare industry ที่กำลังเปลี่ยนไปด้วยพลังของ Python ครับซึ่งมีประเด็นสำคัญคือ การ shift paradigm ไปที่ compute first ซึ่งก็มือถือของเราๆ ท่านๆ แทนที่จะใช้ Mainframe ที่มี format ข้อมูลหลากหลายและทำงานด้วยยากครับ ซึ่งมันเกิดขึ้นได้เพราะยุค Pandemic นี้เราแทบจะลบ Geographic Constraint ออกไปได้เพราะทุกคนเข้าถึงโทรศัพท์และอินเตอร์เน็ตแล้ว อีกสิ่งหนึ่งที่ผมชอบมากคือ Concept Data Fluency ของการที่ใช้ Jupyter Notebook เป็นตัวกลาง format เดียวในการคุยกันตั้งแต่ data engineer, scientist, finance/operation ไปจนถึง Clinician ครับ\nPackaging Python in 2021 — Jeremiah Paige (@ucodery) Talk นี้จริงๆ โฟกัสที่ pyproject.toml ซึ่งเป็นมาตรฐานใหม่ของไฟล์โปรเจ็คใน Python แทน setup.py แต่ผมว่าสิ่งที่ผมชอบมากของ Talk นี้คือการที่พาเราไปดูวิวัฒนาการของ Packaging ตั้งแต่ distutils มาจนถึงปัจจุบันครับ เลยทำให้เราเข้าใจมากขึ้นว่าที่มีอยู่ปัจจุบันเนี่ย มันอาจจะไม่ดีที่สุด แต่มันก็แก้ปัญหามาหลายอย่างแล้ว ใน Talk ยังมีคำแนะนำเกี่ยวกับการ Migrate project จาก build tools เก่าๆ มา pyproject.toml อยู่ด้วยครับ\nPython Performance at Scale — Making Python Faster at Instagram — Dino Viehland ผมอยากบอกว่านี่เป็นหนึ่งใน Talk ที่ผมตั้งตารอคอยที่สุดของงานเลยครับ (เพราะผมไม่ได้สมัคร Language Summit ไป) แต่ใน Talk นี้เราได้เห็นเลยว่า Instagram ก็ยังคงไม่เปลี่ยนไปมากจากที่เราเคยฟังใน Talk ปีที่ผ่านๆ มาครับ โดยยังคงเป็น Django รันอยู่บน uWSGI อยู่ครับ Talk นี้มี Technical terms เยอะมากเกี่ยวกับ CPython interpreters แต่เราได้เห็นเลยว่าแต่ละจุดที่ Optimize ไปมันช่วยเพิ่ม Performance ได้กี่ % ซึ่งสิ่งที่น่าสนใจคือ Metrics ที่เค้าใช้วัดคือ RPS (Request per second underload) ครับ​ซึ่งวัดบน Production จริงๆ ด้วย อีกส่วนที่น่าสนใจคือในส่วนที่เค้ายัง Experiment อยู่ครับ ซึ่งผมสนใจมากตรง Static Python ครับ ซึ่งเป็นความพยายามในการทำให้ Python ได้ Performance ที่ดีขึ้นพอๆ กับ MyPyC หรือ Cython แต่ยังคงเขียนด้วย syntax เดิมๆ ของ Python อยู่\nพอจบ Talk ผมไป join ห้อง discussion ต่อครับเลยได้รู้รายละเอียดนิดหน่อย เพิ่มขึ้นมาคือ โปรเจ็ค Cinder นี้ใช้คนแค่ 20 คนทำมา 3 ปีครับ และเป้าหมายคือการย้าย computation time ลงไปใน JIT ให้มากที่สุด ใน session มีคนถามถึง HHVM ซึ่งเป็นรัน time ของ Hack ด้วยว่าเคยมีแพลนจะแปลง Python ไป HHVM มั้ย ซึ่งเค้าก็บอกว่า สุดท้ายแล้วมันก็ไม่คุ้มที่จะทำทุกอย่างให้เป็นอย่างเดียวครับ\nGradual Typing in Practice — Maggie Moss ผมฟัง Talk เกี่ยวกับ Type annotation มาทุกปี แต่ Talk นี้เป็นครั้งแรกที่ผมเห็น Pyre แบบใช้งานจริงๆ ครับ ซึ่งเป็น Type checker จาก Facebook ที่ออกมาซักพักละ ซึ่งการได้เห็นฟีเจอร์อย่าง pyre-upgrade, strict mode, infer ก็ทำให้อยากปรับไปใช้ตัวนี้แทน mypy ที่ใช้มานานอยู่มากแล้วครับ อีกส่วนที่น่าสนใจคือ gradual typing strategy ที่ทีมนี้ใช้อย่างเช่น การมี dashboard ในการ track type coverage, การให้เวลา engineer เพื่อเพิ่ม type โดยเฉพาะ, ​การ on board new engineer ให้คุ้นเคยกับงานที่ใช้ type แต่แรกเลย หรืออย่างในเรื่องของ Metrics ที่ตัว pyre statistics มี built-in มาให้ครับ แล้วเค้าเก็บข้อมูลตัวนี้ลง Dashboard ไว้ดูในทีมทุกวันเลยว่าเพิ่มขึ้นเท่าไรแล้วครับ\nUnexpected Execution: Wild Ways Code Execution can Occur in Python — Graham Bleaney, Ibrahim Mohamed เรียกได้ว่าเป็นเรื่องบังเอิญมากที่ Talk ในวันที่ 2 ผมเข้าของ Facebook / Instagram หมดเลย (ตอนแรกนึกว่าแค่ 2 Talks บนแต่ Talks นี้เดินสุ่มๆ เข้ามา โดย Talk นี้พูดเกี่ยวกับเรื่อง Remote Code Execution (RCE) ครับว่ามันเกิดขึ้นได้ อย่างไรบ้างตั้งแต่ Pickle, Untrusted input (ซึ่งผมเพิ่งรู้ว่า underlying มัน implement eval() อยู่ทำให้ execute code ได้) ไปจนถึง upload file ซึ่งมี GitHub repository ที่เค้าทำไว้ให้ลองเล่นพวก Vulnerability พวกนี้ด้วยครับ สำหรับผมได้ key takeaway จาก Talk นี้คืออย่า import untrusted code เด็ดขาดและจงแยก Data กับ Code ออกจากกันให้ชัดเจนครับ\nPython Steering Council and PSF Community Address Session สุดท้ายของ Conference Day ครับ ซึ่ง Steering Council มาเล่าให้ฟังหลายๆ เรื่องผมขอสรุปเป็น bullet ละกันเพราะมีหลายเรื่องมาก\nLong Term plan — ทาง Steering Council มองในเรื่อง Compatibility concern กับ Maintainability เป็นหลักครับ รองลงมาเป็นเรื่อง Performance ซึ่งก็มีหลายๆ คนทำเรื่องนี้อยู่เช่นทีม PyPy ส่วนในเรื่องการศึกษาก็พยายามที่จะทำให้ Python ยัง easier to access และปรับปรุงคุณภาพ Document และ error message ต่อไปครับ Short term plan — คงหนีไม่พ้น Python 3.10 ที่กำลังจะออกเร็วๆ นี้ครับที่เพิ่มหลายๆ เรื่องไม่ว่าจะเป็น Pattern matching, parenthesized context manager, typing/performance improvement, better debugging และ Deprecate distutils ที่อยู่กับ Python มานานครับ สิ่งที่น่าสนใจอีกอย่างคือ Python 3.10 เป็นเวอร์ชั่นแรกที่ Cover PEP มากที่สุดตั้งแต่ release มาด้วยครับ สิ่งที่น่าสนใจอีกอย่างที่มีคนถามคือ ไหนๆ เราก็มี type แล้ว Python เราจะเปลี่ยนไปเป็นภาษา Static มั้ยซึ่ง Steering Council ยังยืนยันว่า “Python จะไม่มีวันเป็น Static Type language ครับ แต่ยังคงเป็น Optional Static Type ต่อไป”\nตัวอย่างของ Open networking table ครับ ในห้องนึงก็จะจำกัด 10 หรือ 4 คนแล้วก็ใช้ได้โดยตรงจาก Browser\nIn Summary ต้องบอกว่าถึงแม้ PyCon US จะจัด Online ทำให้เราเข้าถึงงานได้ง่ายขึ้นจากที่ไหนก็ได้ในโลก แต่ต้องยอมรับว่าพอมันเป็นงาน Online หลายๆ อย่างมันก็ขาดหายไป และสำหรับ Introvert แบบผมนี่ ผมบอกได้เลยครับว่า การที่จะกลั้นใจกดเข้าไป join Open space นี่มันใช้พลังหนักมาก ซึ่งหลายๆ คนน่าจะเข้าใจจาก Zoom fatique กัน แต่ก็เป็นประสบการณ์ที่ดีครับที่ได้คุยกันคนที่อยู่อีกฟากโลกทั้งจากอเมริกาและแคนาดาครับ อีกสิ่งหนึ่งที่ไม่ได้หายไป แต่ลำบากขึ้นคือ Swag ครับ ซึ่งอย่างเสื้อกับสติ๊กเกอร์ก็ต้องกดสั่งแยก ส่วนพวกตาม Sponsor Booth ก็ต้องกรอกฟอร์มครับไม่ได้หยิบง่าย เหมือนแต่ก่อน\nก็หวังว่าประสบการณ์ที่ผมเล่ามานี่ จะมีประโยชน์กับใครก็ตามที่สนใจร่วม Online Conference ต่อๆ ไปนะครับ ซึ่งจากสถานการณ์ COVID-19 ในปัจจุบัน ผมว่าน่าจะอีกนานเลยกว่าเราจะได้กลับไปหา Conference แบบ Physical อีกครั้งครับและสุดท้าย อยากปิดด้วยวิดีโอเดียวกับที่ปิดในงานครับ ผมเชื่อว่าใครได้ดูวิดีโอนี้จะเริ่มเข้าใจว่า Python Community มันพิเศษและแตกต่างจากหลายๆ Tech Community ยังไง ลองดูจากลิ้งค์ข้างล่างได้เลยครับ\nArticle written by: Yothin Muangsommuk*, organizer of PyCon APAC 2021 For more information on* PyCon APAC 2021*, checkout:* https://th.pycon.org/\nOriginal post at: https://medium.com/pyconth/my-first-pycon-us-experience-2021-online-2731b3cc15fd\n","permalink":"https://yothinix-com.pages.dev/my-first-pycon-us-experience-2021-online/","summary":"\u003cp\u003eหลายปีที่แล้วผมเคยพูดไว้ว่า \u003ca href=\"/why-i-love-python-so-much/\"\u003eหนึ่งในสิ่งที่ผมชอบเกี่ยวกับภาษา Python ที่สุดคือ Community ครับ\u003c/a\u003e และผ่านมาหลายปี ผมก็ยังยืนยันคำเดิมว่า Python Community เป็นหนึ่งใน Tech community ที่เปิดรับและเป็นมิตรมากที่สุดที่หนึ่งครับ และงานใหญ่ที่สุดประจำปีของชาว Python คืองาน PyCon US หรือหลาย ครั้งก็เรียกกันแค่ PyCon เพราะที่นี่เป็น Original ก่อนจะมี regional PyCon ต่าง ไม่ว่าจะเป็น \u003ca href=\"https://ep2021.europython.eu/\"\u003eEuro Python\u003c/a\u003e, \u003ca href=\"https://2021.pycon.org.au/\"\u003ePyCon AU\u003c/a\u003e, \u003ca href=\"https://th.pycon.org/\"\u003ePyCon APAC\u003c/a\u003e หรือ \u003ca href=\"https://th.pycon.org/\"\u003ePyCon Thailand\u003c/a\u003e ครับ\u003c/p\u003e\n\u003cp\u003eและอย่างที่เรารู้กันดีว่าปี 2021 นี้ยังเป็นอีกปีที่การระบาดของไวรัส COVID-19 ทำให้นี่เป็นปีที่สองที่ PyCon US จัด Online ครับ ซึ่งข้อดีคือ ทำให้เราๆ ที่ไม่ได้อยู่ US สามารถร่วม Conference ได้เพียงแค่มี Computer / Internet เท่านั้นครับ แต่ข้อเสียคือ Timezone จะลำบากหน่อย เพราะเวลา US แทบจะกลับด้านกลางวันกลางคืนกับเวลาไทยเลย\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp\"\n       srcset=\"/my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_bf9d75267b90677f.webp 480w, /my-first-pycon-us-experience-2021-online/1-nG1ixR9VB4Ymg63g8H_QCw_hu_e395f98d65feeab2.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"776\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eวิธีการ Scout หัวข้อผมก็ง่ายๆ ครับทำ Spreadsheet แล้วก็เรียงตาม timeline สำคัญคือ Track ไหนเวลาไหน\u003c/em\u003e\u003c/p\u003e","title":"My first PyCon US experience (2021, Online)"},{"content":"เห็นช่วงนี้สถานการณ์ COVID-19 มันกลับมาหนักอีกรอบ แล้วหลายๆ ทีมต้องปรับตัวมา Work From Home / Work Remotely กันอีกรอบ เลยคิดว่าจากประสบการณ์ที่ทำงานมาหลายปี ผ่าน Work Remotely มาตั้งแต่ Before it was cool นั้น เราได้ Lesson learn อะไรบ้าง หลายอย่างมาจากประสบการณ์จากตัวเราเอง หลายอย่างเราได้จากคนอื่น หลายๆ อย่างได้จากบทความที่อ่านมา ก็ลองเอาไปปรับใช้กันได้ครับ\n⏰ Check-in \u0026amp; Check-out (Offline) สิ่งแรกที่เราควรทำคือ เราบอกทีมว่าเราพร้อมทำงานแล้วนะ ไม่ต่างจากเวลาเราเข้าไปทำงานในที่ทำงานปกติแล้วเราทักทายเพื่อนร่วมทีมเวลาเดินทางมาถึงที่ทำงานใช่มั้ยครับ ซึ่งการ check-in แบบนี้นอกจากจะช่วยให้ทีมรู้ว่าเราพร้อมทำงานแล้วแบบ Explicit แล้วยังเป็นโอกาสที่เราจะได้ใช้เวลาคุยเล่นด้วย ในช่วงเวลาที่เรายังไม่ลงไปโฟกัสกับงานเต็มตัว\nในอีกมุมนึง เวลาเราทำงานปกติจะกลับบ้าน เราก็บอกลาคนในทีมใช่มั้ยครับ ว่า \u0026ldquo;เรากลับบ้านแล้วนะ\u0026rdquo; โดยหลายๆ ครั้งพอเรา Adapt มา Work remotely เรามักจะลืมสิ่งนี้ไป ซึ่งผมบอกได้เลยว่านี่เป็นสิ่งสำคัญอย่างนึงเลย ที่เราจะบอกทีมว่าโอเค เราเลิกงานแล้วนะ เราอาจจะตอบแชทได้ แต่ไม่ 100% เหมือนตอนเรา Check-in อยู่นะ\nอีกสิ่งหนึ่งที่เราชอบลืม Check-in \u0026amp; Check-out กันคือ ตอนพักเที่ยงครับ ซึ่งผมจำได้เลยว่าหลายปีก่อนที่ผม Work Remotely ใหม่ๆ ผมเถียงหัวหน้าผมขาดใจเลยว่า ผมยังไม่หิว เพราะเวลาเราทำงานอยู่บ้านเราจะ Flow มาก แต่หัวหน้าผมให้เหตุผลกลับมาว่า มันสำคัญมากที่เราต้อง Balance เวลาที่เราทำงานกับเวลาพัก ตอนนี้เหมือนจะไหว แต่ Long run มันจะทำให้เวลาเราเสียสมดุลไปหมด เพราะฉะนั้นเที่ยงก็พัก กลับมาก็ check-in ด้วยนะครับ\n🛀 Take a shower \u0026amp; Get dressed อันนี้เป็นเรื่องเล็กๆ น้อยๆ ครับ คือ พอเราอยู่บ้านเนี่ย แล้วเรา Work remotely เราตื่นมาแล้ว เราคิดออก เราก็ชอบที่จะพุ่งไปเปิด Computer แล้วรัวโค้ดที่คิดออกลงไปในคีย์บอร์ดเลย ซึ่งถ้านานๆ ครั้งโอเค ถ้าเรารัวพอใจแล้วก็กลับไปใช้ชีวิตปกติ แต่หลายครั้งเราจะติดนิสัย ตื่นมายังไงก็ยังงั้นทั้งวันเลยครับ ซึ่งอันนี้ผมเกิดกับตัวเองหลังจาก Work remotely ไปได้ซักระยะหนึ่ง (ใหม่ๆ ไม่ค่อยเจอ) เพราะเราเริ่มไม่ต้องคอยแคร์สายตาคนอื่นแล้ว\nผมจะบอกว่า จังหวะที่เราอาบน้ำแล้ว แต่งตัวในตอนเช้าแต่ละวัน มันเป็นการที่เราดึงตัวเองออกมาจาก Context ของงานที่ชัดมากวิธีนึงครับ ถึงแม้มันจะมีเรื่องจริงหรือตลกหลายๆ ครั้งที่บอกว่า เราชอบคิดโค้ดออกเวลาอาบน้ำนั้น แต่นั่นก็เพราะหลังจากเราดึงตัวเองถอยออกมาจาก Context ของงานปกติแล้วครับ อีกอย่างนึงคือ เวลาเราแต่งตัว (เกือบๆ) เหมือนทำงานปกติ มันจะช่วยให้ตัวเรารับรู้ว่า นี่คือเวลาทำงานนะ ไม่ใช่เวลานอนกลิ้งในชุดนอน เหมือนที่ผ่านมาทั้งคืน\n💬 Over communicate ≠ Alway communicate ส่วนตัวผมยกให้เรื่องนี้เป็นเรื่องที่ยากที่สุดสำหรับทีมที่เพิ่งจะ Work remotely ใหม่ๆ ครับ ด้วย Nature ของ developer ที่เรามักจะโฟกัสกับปัญหา จนรู้ตัวอีกทีเวลาก็ผ่านไปหลายชั่วโมง ปัญหาที่เกิดขึ้นคือ คนในทีมไม่ได้มองเห็นว่าเราจมอยู่กับปัญหาเหมือนตอนเรานั่งอยู่ด้วยกัน\nอีกเรื่องนึงที่ผมค้นพบกับหลายๆ คนที่เพิ่งจะ Work remotely ใหม่ๆ คือเราจะกังวลกับการขอความช่วยเหลือมากกว่าปกติ อย่างมีนัยยะสำคัญ เพราะการใช้ @here @everyone ในแชต มันรู้สึกเหมือนการตะโกนกลางที่ทำงานจนทุกคนหันมา ทำให้หลายๆ คนเลือกที่จะทักส่วนตัวแทน แล้ว Knowledge context ในทีมจะหายไปเยอะมากในช่วงนี้ครับ\nโอเคกลับมาที่ Practice นะครับ Over communicate จะช่วยเราแก้ปัญหาเรื่องนี้ได้ระดับนึงคือ เราจะ Explicit ว่าเรากำลังทำอะไรอยู่กับทีมเสมอ ซึ่งนอกจาก Daily standup การพิมพ์ออกไปลอยๆ ในห้องรวมของทีมว่าเรากำลังทำอะไรอยู่ แค่นั้นก็เพียงพอแล้วครับ และถ้าเราต้องการความช่วยเหลือในวินาทีแรกที่เราต้องการ ให้เราพิมพ์ออกไปเลย เพราะว่าคนที่เราต้องการความช่วยเหลือนั้นเราคาดหวังได้เลยว่าจะไม่ตอบทันที\nอย่างไรก็ตามเรื่องนี้มีความยากอย่างนึงตรงที่พอเราพูดถึง Over communicate หลายคนจะเข้าใจผิดว่ามันคือการ Alway communicate ก็คือเราอยู่ในแชตทั้งวัน ตอบทั้งวัน คำถามคือ \u0026ldquo;แล้วเราทำงานตอนไหนนะ?\u0026rdquo; เพราะฉะนั้น Over, but not always นะครับ ให้เวลากับการทำงานจริงๆ เป็นสิ่งสำคัญที่สุดครับ\n😴 Break regulary (Once every hours) ข้อนี้ผมค้นพบว่า ไม่ต้องเป็นทีม Remote ก็เอาไป Practice ได้นะครับ จะเหมือนกับเรื่องที่ผมไม่ยอมกินข้าวข้างบนนะแหละ คือตอนเริ่มต้นวัน เราอาจจะรู้สึกว่า เราทำงานได้ติดต่อกันหลายๆ ชั่วโมง แต่การเลือกที่จะทำอย่างนั้นหลายครั้ง ตอนบ่ายเราจะไม่เหลือพลังแล้วครับ เพราะฉะนั้น ถ้าเป็นไปได้ พยายามพักบ่อยๆ ครับ อย่างน้อยชั่วโมงละครั้งก็ยังดี อาจจะ 5-10 นาทีก็ว่าไป\nซึ่ง Practice ที่มาช่วยเรื่องนี้ได้ดีที่สุดน่าจะไม่พ้น Pomodoro ครับ ที่ช่วยเราแบ่งเวลาทำงานเป็นรอบๆ โฟกัส 25 พัก 5 หรือบางคนอาจจะปรับรอบให้เหมาะสมกับการทำงานของแต่ละคน ซึ่งเอาที่สะดวกครับ แล้วชีวิตเราจะสามารถ Maintain พลังงานไปจนจบวันได้ โดยไม่เหนื่อยเกินไปครับ\n📑 Adapt to asynchronous communication ส่วนนี้ผมเล่าไปนิดนึงแล้วตอน Over, but not always communicate ครับ แต่อยากจะเสริมว่า ช่องทางการสื่อสารที่เรามีอย่างแชตนั้นโดยธรรมชาติแล้วมันถูกออกแบบมาเป็น Asynchronous ครับ เราไม่จำเป็นต้องอ่านมันตลอดเวลา แต่เราต้องมาอ่านมันเรื่อยๆ ซึ่งคำว่าเรื่อยๆ เนี่ยเราอาจจะกลับมาเช็คทุกเบรค หรือทุกชั่วโมงกำลังดีครับ จะทำให้เรามีเวลาโฟกัสกับงาน และมีเวลา catch up กับทีม โดยที่ยังไม่ทิ้งห่างเกินไป\nอีกข้อนึงคือเรื่องประชุมครับ ถ้าเราคิดว่าการประชุมนั้นไม่จำเป็นต้องมีคนมานั่งรวมกันแล้วคูณพลังกันทุกคน (ซึ่งการประชุมใน Remote environment มันยากอยู่แล้ว) ทางเลือกที่เป็น alternative อีกอย่างคือการเขียนครับ หลายๆ ทีมเลือกที่จะ discuss หลายๆ เรื่องใน GitHub issues, Discourse แทนที่จะเลือก video call มา ที่สำคัญอีกอย่างนึงคือ เวลาเรา video call จังหวะ dead air เป็นเรื่องที่เกิดขึ้นง่ายมากครับ เพราะทุกคนเท่ากันตอน video call เพราะฉะนั้นพยายามนึกถึงเรื่อง over communicate ไว้นะครับ ไม่ต้องรอให้คนอื่นเริ่มก่อน เราเริ่มที่ตัวเองได้เลย\nแต่เรื่องนี้ต้องระวังอย่างนึงนะครับ หลายๆ ครั้งเราจะติดช่องทาง asynchronous ไปใน conversation ที่มันต้องการ synchronous สัญญาณอย่างนึงที่เราจะเห็นชัดคือแชตเอียงขวา หรือเอียงซ้าย หรือการที่คนๆ นึงมีความต้องการมากกว่าอีกคนนึง ซึ่ง วิธีนึงที่แก้ได้ แทนที่เราจะพิมพ์ข้อความเยอะๆ หรือรัวๆ เราอาจจะเลือกนัด Call, video conference กับคนนั้นแทนครับ ซึ่งหลายๆ ครั้งแทนที่เราจะพิมพ์คุยกันเป็นชั่วโมง การ call แค่ 5 นาทีก็ตอบคำถามได้แล้วครับ\n🙇‍♂️ Respect the team \u0026amp; yourself ข้อสุดท้ายที่ผมอยากจะพูดถึงคือ เวลาที่เราทำงาน Remote เนี่ย มันไม่มีใครเห็นหรอกว่าเราทำงาน แต่ถึงแม้จะไม่มีใครเห็นเรา แต่เราก็ต้องเคารพตัวเองด้วยว่า นี่คือเวลางานนะ มันไม่ใช่เวลาที่เราจะเอาเปรียบคนอื่น ถึงแม้มันจะมีช่องทางและโอกาสให้ทำมากขึ้นก็ตามครับ\nในอีกมุมนึง เวลาเราเห็นเพื่อนในทีมเงียบหายไป เราก็ต้องพยายามเชื่อใจเค้าเช่นกันว่าเค้ากำลังพยายามทำงานสุดความสามารถเค้าอยู่ เพราะเราไม่ได้เห็นหน้ากันเหมือนก่อนหน้านี้แล้ว ครับ ซึ่งของแบบนี้ใน remote environment เป็นเรื่องละเอียดอ่อนมากครับ แต่อย่างน้อยถ้าเราเริ่มที่ตัวเองก่อนได้ ปัญหาก็จะลดน้อยลงแล้วครับ\nก็ลองไปปรับใช้กันดูได้ครับ กับหลายๆ เทคนิคที่ผมพูดถึงข้างบน แต่ผมอยากจะย้ำอย่างนึงว่า ไม่ใช่ทุกเทคนิคจะแก้ปัญหาได้กับทุกทีมครับ เพราะฉะนั้น หลายๆ วิธีที่ผมทำแล้วเวิร์ค อาจจะไม่เวิร์คกับอีกทีม ถ้าใครมีเทคนิคอื่นๆ ที่ช่วยทำให้เรามีความสุขขึ้นตอนทำงานแบบ Remote แชร์ให้ฟังหน่อยได้มั้ยครับ ผมอยากเรียนรู้จากคุณมากเลย แล้วก็สุดท้าย ขอบคุณที่อ่านมาถึงตรงนี้ครับ 🙏 🤣\n","permalink":"https://yothinix-com.pages.dev/work-from-home-yangaingaihyangmiikhwaamsukh/","summary":"\u003cp\u003eเห็นช่วงนี้สถานการณ์ COVID-19 มันกลับมาหนักอีกรอบ แล้วหลายๆ ทีมต้องปรับตัวมา Work From Home / Work Remotely กันอีกรอบ เลยคิดว่าจากประสบการณ์ที่ทำงานมาหลายปี ผ่าน Work Remotely มาตั้งแต่ Before it was cool นั้น เราได้ Lesson learn อะไรบ้าง หลายอย่างมาจากประสบการณ์จากตัวเราเอง หลายอย่างเราได้จากคนอื่น หลายๆ อย่างได้จากบทความที่อ่านมา ก็ลองเอาไปปรับใช้กันได้ครับ\u003c/p\u003e\n\u003ch2 id=\"-check-in--check-out-offline\"\u003e\u003cstrong\u003e⏰ Check-in \u0026amp; Check-out (Offline)\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eสิ่งแรกที่เราควรทำคือ เราบอกทีมว่าเราพร้อมทำงานแล้วนะ ไม่ต่างจากเวลาเราเข้าไปทำงานในที่ทำงานปกติแล้วเราทักทายเพื่อนร่วมทีมเวลาเดินทางมาถึงที่ทำงานใช่มั้ยครับ ซึ่งการ check-in แบบนี้นอกจากจะช่วยให้ทีมรู้ว่าเราพร้อมทำงานแล้วแบบ Explicit แล้วยังเป็นโอกาสที่เราจะได้ใช้เวลาคุยเล่นด้วย ในช่วงเวลาที่เรายังไม่ลงไปโฟกัสกับงานเต็มตัว\u003c/p\u003e\n\u003cp\u003eในอีกมุมนึง เวลาเราทำงานปกติจะกลับบ้าน เราก็บอกลาคนในทีมใช่มั้ยครับ ว่า \u0026ldquo;เรากลับบ้านแล้วนะ\u0026rdquo; โดยหลายๆ ครั้งพอเรา Adapt มา Work remotely เรามักจะลืมสิ่งนี้ไป ซึ่งผมบอกได้เลยว่านี่เป็นสิ่งสำคัญอย่างนึงเลย ที่เราจะบอกทีมว่าโอเค เราเลิกงานแล้วนะ เราอาจจะตอบแชทได้ แต่ไม่ 100% เหมือนตอนเรา Check-in อยู่นะ\u003c/p\u003e\n\u003cp\u003eอีกสิ่งหนึ่งที่เราชอบลืม Check-in \u0026amp; Check-out กันคือ ตอนพักเที่ยงครับ ซึ่งผมจำได้เลยว่าหลายปีก่อนที่ผม Work Remotely ใหม่ๆ ผมเถียงหัวหน้าผมขาดใจเลยว่า ผมยังไม่หิว เพราะเวลาเราทำงานอยู่บ้านเราจะ Flow มาก แต่หัวหน้าผมให้เหตุผลกลับมาว่า มันสำคัญมากที่เราต้อง Balance เวลาที่เราทำงานกับเวลาพัก ตอนนี้เหมือนจะไหว แต่ Long run มันจะทำให้เวลาเราเสียสมดุลไปหมด เพราะฉะนั้นเที่ยงก็พัก กลับมาก็ check-in ด้วยนะครับ\u003c/p\u003e","title":"Work From Home ยังไงให้ยังมีความสุข"},{"content":"เหตุเกิดจากเมื่อวานมีน้องในทีมอยู่ดีๆ มาถามว่า \u0026ldquo;พี่เอาเวลาตอนไหนไปอ่านหนังสือนะ\u0026rdquo; ตอนนั้นคือไม่รู้ว่าจะมีเวลาเท่าไรเลยตอบแบบสั้นๆ ไป\nทุกช่วงเวลาที่ว่างนะแหละ\nแล้วหลังจากนั้นผมก็ยกตัวอย่างช่วงเวลาที่ว่างที่พอจะนึกออกเช่น ระหว่างรอสั่งข้าว, ยืนบนรถไฟฟ้า,​ นั่งขี้, ก่อนนอน,​ ตื่นนอน ฯลฯ แต่กลัวว่าจะไม่เกทเลยรู้สึกว่าต้องมีเขียนบล็อกต่อนี่แหละ\nมันเริ่มมาจากความเจ็บปวด จริงๆ มันมีที่มาว่าผมรู้สึกแย่มากที่ตัวเองไม่ค่อยมีเวลาได้อ่านหนังสือ แบบ เห้ย เรารู้นะว่าการอ่านหนังสือมันดี พออ่านแล้วชีวิตเราดีขึ้น เราก็อยากจะอ่านมัน แต่แค่อยากมันไม่ได้ไง ยิ่งช่วงหลังๆ ที่มีสิ่งเร้าเยอะมาก เช่น พอกลับถึงคอนโด ก็เปิดทีวีเลย หรือถ้าว่างก็หยิบมือถือขึ้นมาไถๆ Facebook, Twitter ทำให้เราไม่มีที่ว่างให้หนังสือเลย\nแต่ถึงจะไม่มีเวลาให้หนังสือ แต่ผมสามารถซื้อหนังสือมาเติมได้เรื่อยๆ ด้วยจังหวะชีวิตที่พอเข้าฟิตเนส แล้วออกมามี Routine ว่าจะต้องแวบเข้าไปร้านหนังสือ มันทำให้จำได้เลยว่า เล่มไหนเพิ่งวางแผง เล่มไหนเล็งไว้ก่อนหน้านี้ คือสามารถ git diff ชั้นหนังสือดูได้เลยว่าอะไรเปลี่ยนไปตรงไหน\nแก้ที่พฤติกรรมก่อนเลย ตอนช่วงที่ผมแบบไม่ไหวแล้วโว้ย \u0026ldquo;อยากอ่านหนังสือ\u0026quot;​ เป็นช่วงเวลากับที่ผมเริ่มทำ Bujo ใหม่อีกรอบแล้วเอา tooling อย่าง Habit Tracker มาช่วยด้วย (อ่านได้ในบล็อก เรากลับมาทำ BuJo ได้หนึ่งเดือนแล้ว ครับ) แต่ที่ผมไม่ได้พูดถึงในนั้นมีอยู่ 2 เรื่องครับ\nตอนผมทำ Tracker ผม Challenge ตัวเองหนักมากว่าต้องได้ Streak เยอะๆ คือไม่ต้องอ่านเยอะ แต่ต้องอ่านทุกวัน มันเลยค่อยๆ เริ่มจากอ่านใน BTS ตอนที่ยังต้องนั่งยาวๆ ไป 40 นาที ไปกลับก็​ 1 ชั่วโมง 20 นาทีละ ที่จะได้อยู่กับหนังสือ จังหวะที่ระบายสีลงในช่องแต่ละวันว่าเราได้อ่าน นี่มันฟินมากครับ ตอนผ่านไปอาทิตย์แรกนี่ก็ฟินแล้ว ว่าโห เราทำได้ติดต่อกันถึง 7 วันเลยเหรอ แล้วด้วยความกลัวเสียสถิติ ผมเลยพยายามทำลายสถิติตัวเองมากขึ้นทุกวัน ซึ่งตอนแก้พฤติกรรมมันเหนื่อยนะ และผมอยากให้รางวัลกับมันบ้าง จริงๆ เป้าหมายผมตอนนั้นง่ายมาก คือผมอยากได้ Kindle มาตั้งแต่สมัยเรียนมหาลัยละ แล้วก็ไม่มีโอกาสซักที พอถามแฟน แฟนก็บอกว่า อยากได้มาเดี๋ยวก็เบื่อ เลย Challenge กับตัวเองว่า ถ้าอ่านหนังสือได้ 30 วันติด จะถอยเลย ซึ่งทำได้จริงๆ นะ แล้วก็ถอยมาเลย Kindle Paperwhite ทำให้รู้สึกสนุกกับตอนอ่านหนังสือมากขึ้นอีก\nเพราะทุกครั้งที่หยิบ Kindle ขึ้นมาอ่าน มันจะคอยเตือนว่า กว่าจะได้อิเครื่องนี้มาเนี่ย ต้องอ่านหนังสือติดต่อกัน 30 วันเลยนะ \u0026ldquo;ใช้ให้คุ้มนะ\u0026rdquo; - เสียงตัวเองตอนพยายามเปลี่ยนพฤติกรรมบอกมา\nเดี๋ยวนี้ยัง Track อยู่นะ แต่ใน Kindle แทน ง่ายกว่า\nวิธีที่ไม่เวิร์ค (สำหรับผม) จริงๆ พอเราไป search Google มันจะมีวิธีมากมายที่จะ \u0026ldquo;ช่วยให้เราอ่านหนังสือได้มากขึ้น\u0026rdquo; อันนี้คือสิ่งที่ผมเคยลองแล้วไม่เวิร์ค\nอ่านก่อนนอน/ตื่นนอนทุกวัน - ก่อนอื่นเลยผมยังอ่าน ก่อนนอน/ตื่นนอน อยู่นะ แต่สิ่งสำคัญคือ \u0026ldquo;ไม่ทุกวัน\u0026rdquo; เพราะบางวันเราเหนื่อยจริงๆ ก็ไม่ต้องฝืนครับ ไม่งั้นหนังสือ มันจะตกมาทับหัวเราได้ แต่ในเคสตอนตื่น นี่ก็ไม่ไหวเพราะบางทีมันก็ง่วง จนอ่านๆ ไปแล้วตาหลายหลงบรรทัดบ่อยมาก สำหรับข้อนี้ผมเลยทำบ้าง ถ้ามีความอยาก แต่ไม่ได้ทำ \u0026ldquo;ทุกวัน\u0026rdquo;\nพกหนังสือติดตัวไว้ 2-3 เล่ม จะได้อ่านได้ - ส่วนตัวผมเป็นคนเบื่อง่ายครับ เพราะฉะนั้นผมเลยไม่อ่านหนังสือเล่มใดเล่มหนึ่งยาวๆ ติดต่อกัน แต่จะอ่านสลับไป สลับมาหลายๆ เล่มแทน ซึ่งอันนี้ปัญหาหลักเลยคือมันหนัก แต่แก้ได้ด้วย Kindle ครับ\nอ่านวันละหน้า - อันนี้ก็ไม่เวิร์คสำหรับผมนะ เพราะเวลาอ่านแล้ว จะชอบไปจนจบ Chapter หรือย่อหน้านึงก็ยังดี พอบังคับตัวเองให้อยู่ในหน้าเดียวแล้ว ผมค้างคาหนะ เอะหรือว่ามันเป็น Goal ของวิธีนี้นะ\nวิธีที่เวิร์ค (สำหรับผมเช่นกัน) อย่าไปจำกัดมันแค่ Physical book - คือหนังสือ มันมีหลาย Format ไง จะไปรออ่านเป็นเล่มจริงๆ ก็กว่าจะถึงบ้าน (แต่บางเล่มมันก็มีแต่ Physical จริงๆ) ถึงจะได้อ่าน หรือต้องแบกไปถึงจะได้อ่าน ซึ่งพอมาอ่านบน ebook มันก็จะเข้าถึงได้ตลอดเวลามากกว่า ขี้เกียจหยิบ Kindle หยิบมือถือได้ มีจังหวะว่างตอนเปิดคอมก็อ่านในคอมได้ คืออ่านได้ทุกที่ ทุกเวลาครับ ตราบใดที่มี electronics device แต่ข้อเสียคือ หนังสือไทยดีๆ ยังไม่อยู่ใน ebook ครับ ช่วงเวลานักไถ - ผมเชื่อว่าถ้าเรามีเวลาหยิบมือถือมาไถ Facebook/Twitter ได้ ช่วงเวลานั้นแหละ เราก็อ่านหนังสือได้เช่นกัน แล้วนี่น่าจะเป็นตัวหลักเลยที่ทำให้เรารู้สึกว่าเราไม่ได้อ่าน แต่จะทำไม่ได้เลย ถ้าขาดข้อล่างครับ ย้ายแอพอ่าน ebook มาไว้ในหน้าแรกของโทรศัพท์ - ท่านี้ผมได้มาจากหนังสือ Make Time เลยคือ ถ้าเราอยากจะทำอะไร เราต้องลด Friction มันให้มากที่สุด และถ้าอยากเลิกทำอะไร ก็ต้องเพิ่ม Friction มันให้มากที่สุดครับ การที่แอพอ่านหนังสือ มันอยู่หน้าแรกทำให้เปิดมา เราจะ \u0026ldquo;เห็น\u0026rdquo; ว่าเราอ่านหนังสือได้นะ หรือจะไปไถ Facebook แทน Choice is yours ครับ เอาไปโม้ - อ่านอย่างเดียว มันไม่ฟินครับ ต้องเอาไปโม้หรือเอาไปแชร์ด้วย ซึ่งอาจจะเขียนบล็อก โพส Facebook หรือเล่าให้เพื่อนฟัง ผมค้นพบอย่างนึงว่า จังหวะตอนที่เราแชร์ เราได้ Defragment เรื่องที่เราอ่านมาด้วย และ Feedback ตอนเราได้จากการเล่าให้คนอื่นฟัง มันเป็นกำลังใจที่พาเราอ่านต่อไปครับ พยายามรักษา Momentum เอาไว้ จริงๆ เราอยากอ่านหนังสือ หลายๆ ครั้ง เราไม่ได้อยากอ่านเองหรอก แต่เราไปเห็นคนอื่นอ่าน คนอื่นสรุปว่า เล่มนั้นดี เล่มนี้โดน เอาคำคมจากเล่มนั้นมาแชร์ จังหวะที่เราเห็นอะครับ มันจะเกิดความปรารถนา อย่างแรงกล้า ที่อยากจะไปอ่านเล่มนั้น ซึ่งถ้าโชคดีเรามีจังหวะพอดี เราก็อาจจะกดซื้อเล่มนั้นมา แล้วอ่านเลย ในขณะที่ Momentum นั้นยังมีอยู่\nซึ่ง Momentum ไม่ได้มาในรูปแบบเดียว แต่บางครั้ง เราต้องการแก้ปัญหาอะไรบางอย่างในชีวิต เช่น เราอยากรู้เรื่อง Service Design มีหนังสืออะไรให้อ่านมั่ง หรือ เราอยากจะเข้าใจ Self Esteem ในตัวเรามีอะไรให้เราอ่านมั่ง ซึ่งนี่ก็เป็นอีกวิธีที่ทำให้ Momentum การอ่านมันต่อเนื่องไปได้ และหลายๆ ครั้งมันจะถึงจุดที่เราร้อง เชี่ยยยย นี่แหละสิ่งที่เราตามหา\nใช้ Save ของ Facebook ให้เป็นประโยชน์ครับ\nก็ประมาณนี้ครับ ผมไม่รู้ว่าจะช่วยให้เข้าใจมากขึ้นมั้ย ถ้าใครมีเทคนิคอะไรอยากแชร์ ผมยินดีรับฟังมากครับ แล้วถ้ามีหนังสืออะไรอยากแนะนำก็จัดเลยครับ ขอบคุณทุกคนที่อ่านมาถึงตรงนี้มาก ผมซาบซึ้งจริงๆ นะ\n","permalink":"https://yothinix-com.pages.dev/when-to-read/","summary":"\u003cp\u003eเหตุเกิดจากเมื่อวานมีน้องในทีมอยู่ดีๆ มาถามว่า \u0026ldquo;พี่เอาเวลาตอนไหนไปอ่านหนังสือนะ\u0026rdquo; ตอนนั้นคือไม่รู้ว่าจะมีเวลาเท่าไรเลยตอบแบบสั้นๆ ไป\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eทุกช่วงเวลาที่ว่างนะแหละ\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eแล้วหลังจากนั้นผมก็ยกตัวอย่างช่วงเวลาที่ว่างที่พอจะนึกออกเช่น ระหว่างรอสั่งข้าว, ยืนบนรถไฟฟ้า,​ นั่งขี้, ก่อนนอน,​ ตื่นนอน ฯลฯ แต่กลัวว่าจะไม่เกทเลยรู้สึกว่าต้องมีเขียนบล็อกต่อนี่แหละ\u003c/p\u003e\n\u003ch2 id=\"มนเรมมาจากความเจบปวด\"\u003e\u003cstrong\u003eมันเริ่มมาจากความเจ็บปวด\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eจริงๆ มันมีที่มาว่าผมรู้สึกแย่มากที่ตัวเองไม่ค่อยมีเวลาได้อ่านหนังสือ แบบ เห้ย เรารู้นะว่าการอ่านหนังสือมันดี พออ่านแล้วชีวิตเราดีขึ้น เราก็อยากจะอ่านมัน แต่แค่อยากมันไม่ได้ไง ยิ่งช่วงหลังๆ ที่มีสิ่งเร้าเยอะมาก เช่น พอกลับถึงคอนโด ก็เปิดทีวีเลย หรือถ้าว่างก็หยิบมือถือขึ้นมาไถๆ Facebook, Twitter ทำให้เราไม่มีที่ว่างให้หนังสือเลย\u003c/p\u003e\n\u003cp\u003eแต่ถึงจะไม่มีเวลาให้หนังสือ แต่ผมสามารถซื้อหนังสือมาเติมได้เรื่อยๆ ด้วยจังหวะชีวิตที่พอเข้าฟิตเนส แล้วออกมามี Routine ว่าจะต้องแวบเข้าไปร้านหนังสือ มันทำให้จำได้เลยว่า เล่มไหนเพิ่งวางแผง เล่มไหนเล็งไว้ก่อนหน้านี้ คือสามารถ git diff ชั้นหนังสือดูได้เลยว่าอะไรเปลี่ยนไปตรงไหน\u003c/p\u003e\n\u003ch2 id=\"แกทพฤตกรรมกอนเลย\"\u003e\u003cstrong\u003eแก้ที่พฤติกรรมก่อนเลย\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eตอนช่วงที่ผมแบบไม่ไหวแล้วโว้ย \u0026ldquo;อยากอ่านหนังสือ\u0026quot;​ เป็นช่วงเวลากับที่ผมเริ่มทำ Bujo ใหม่อีกรอบแล้วเอา tooling อย่าง Habit Tracker มาช่วยด้วย (อ่านได้ในบล็อก \u003ca href=\"/bujo\"\u003eเรากลับมาทำ BuJo ได้หนึ่งเดือนแล้ว\u003c/a\u003e ครับ) แต่ที่ผมไม่ได้พูดถึงในนั้นมีอยู่ 2 เรื่องครับ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eตอนผมทำ Tracker ผม Challenge ตัวเองหนักมากว่าต้องได้ Streak เยอะๆ คือไม่ต้องอ่านเยอะ แต่ต้องอ่านทุกวัน มันเลยค่อยๆ เริ่มจากอ่านใน BTS ตอนที่ยังต้องนั่งยาวๆ ไป 40 นาที ไปกลับก็​ 1 ชั่วโมง 20 นาทีละ ที่จะได้อยู่กับหนังสือ\u003c/li\u003e\n\u003cli\u003eจังหวะที่ระบายสีลงในช่องแต่ละวันว่าเราได้อ่าน นี่มันฟินมากครับ ตอนผ่านไปอาทิตย์แรกนี่ก็ฟินแล้ว ว่าโห เราทำได้ติดต่อกันถึง 7 วันเลยเหรอ แล้วด้วยความกลัวเสียสถิติ ผมเลยพยายามทำลายสถิติตัวเองมากขึ้นทุกวัน\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eซึ่งตอนแก้พฤติกรรมมันเหนื่อยนะ และผมอยากให้รางวัลกับมันบ้าง จริงๆ เป้าหมายผมตอนนั้นง่ายมาก คือผมอยากได้ Kindle มาตั้งแต่สมัยเรียนมหาลัยละ แล้วก็ไม่มีโอกาสซักที พอถามแฟน แฟนก็บอกว่า อยากได้มาเดี๋ยวก็เบื่อ เลย Challenge กับตัวเองว่า ถ้าอ่านหนังสือได้ 30 วันติด จะถอยเลย ซึ่งทำได้จริงๆ นะ แล้วก็ถอยมาเลย Kindle Paperwhite ทำให้รู้สึกสนุกกับตอนอ่านหนังสือมากขึ้นอีก\u003c/p\u003e","title":"เอาเวลาที่ไหนไปอ่านหนังสือนะ 📚🤔"},{"content":"สมมติว่าเรามีโจทย์ที่ต้องยิง HTTP Request เพื่อดึง resource มาจาก Web service อื่นหลายๆ ที่ ถ้าเราไม่คิดอะไรเราก็อาจจะเขียนโค้ดให้ ยิงทีละตัวแบบ Synchronous ไปได้ แต่ถ้าแต่ละ Request ไม่ได้ขึ้นต่อกัน เราจะมีตัวเลือกมากขึ้นผ่านการยิงแบบ Asynchronous ครับ ซึ่งผมเพิ่งรู้ว่า Java มันทำได้\nExample สมมติว่าเรามี Service ที่ไว้ยิง HTTP Request ไปที่ API อื่นแบบง่ายๆ หน้าตาประมาณนี้\n@Service public class ActivityService { RestTemplate restTemplate = new RestTemplate(); public ResponseSecond getEndpointOne() { String url = \u0026#34;http://localhost:8000/1\u0026#34;; ResponseSecond response = restTemplate.getForObject(url, ResponseSecond.class); return response; } } และมี Controller ที่เรียกใช้ Service นี้หน้าตาประมาณนี้\n@RestController public class ActivityController { @Autowired ActivityService activityService; @GetMapping(path = \u0026#34;/\u0026#34;) public ResponseEntity\u0026lt;String\u0026gt; getActivity() throws Throwable { try { ResponseSecond one = activityService.getEndpointOne(); ResponseSecond two = activityService.getEndpointOne(); ResponseSecond three = activityService.getEndpointOne(); String response = \u0026#34;\u0026#34;; if (one != null \u0026amp;\u0026amp; two != null \u0026amp;\u0026amp; three != null) { response = one.getMessage() + \u0026#34; \u0026#34; + two.getMessage() + \u0026#34; \u0026#34; + three.getMessage(); } return ResponseEntity.ok(response); } catch (Exception e) { throw e.getCause(); } } ก็ดูทำงานได้ปกติใช่มั้ยครับ แต่สิ่งที่เกิดคือ มันจะทำงานแบบ Synchronous ก็คือ getEndpointOne แต่ละตัวต้องถูกทำให้เสร็จก่อนที่จะเรียกตัวถัดไป ซึ่งสมมติว่าแต่ละ Endpoint ต้องทำงาน 1 วิ นั่นคือ 3 วิเลยกว่า controller นี้จะวิ่งจนครบ loop\nทำให้มัน Async เถอะ อย่างแรกที่เราต้องแก้คือ Service ครับ โดยเราจะใช้ความสามารถของ Annotation ชื่อ @Async มาทำให้ Method ของเรานั้นสามารถที่จะเรียกแบบ Asynchronous ได้ แต่มีข้อแม้สองข้อครับคือ\nMethod ที่เราจะทำให้เป็น Async นั้นต้องเป็น public method Method ที่เรียกใช้งาน Async Method นั้นต้องอยู่คนละ Class กันครับ เพราะ Async ทำ self-invocation ไม่ได้ พอรู้แบบนี้แล้ว ขั้นแรกคือเราต้องแปลง method ที่เราจะทำให้มันเป็น async ให้หน้าตาประมาณนี้ครับ\n@Async public CompletableFuture\u0026lt;ResponseSecond\u0026gt; getEndpointOne() { String url = \u0026#34;http://localhost:8000/1\u0026#34;; ResponseSecond response = restTemplate.getForObject(url, ResponseSecond.class); return CompletableFuture.completedFuture(response); } จะเห็นว่ามีสิ่งที่เพิ่มขึ้นมา 3 อย่างคือ\n@Async ที่เป็นการระบุว่า Method นี้สามารถเรียกใช้แบบ Asynchronous ได้ Return type signature จะถูกครอบด้วย CompletableFuture\u0026lt;T\u0026gt; ครับ Return value จะต้องเพิ่ม CompletableFuture.completedFuture() ครอบไปครับ ในส่วนของ method ที่เรียกใช้งาน Async method นั้นจะเปลี่ยนไปหน้าตาประมาณนี้ครับ\npublic ResponseEntity\u0026lt;String\u0026gt; getAsync() throws Throwable { try { CompletableFuture\u0026lt;ResponseSecond\u0026gt; one = activityService.getEndpointOne(); CompletableFuture\u0026lt;ResponseSecond\u0026gt; two = activityService.getEndpointOne(); CompletableFuture\u0026lt;ResponseSecond\u0026gt; three = activityService.getEndpointOne(); CompletableFuture.allOf(one, two, three); String response = \u0026#34;\u0026#34;; if (one != null \u0026amp;\u0026amp; two != null \u0026amp;\u0026amp; three != null) { response = one.get().getMessage() + \u0026#34; \u0026#34; + two.get().getMessage() + \u0026#34; \u0026#34; + three.get().getMessage(); } return ResponseEntity.ok(response); } catch (Exception e) { throw e.getCause(); } } จะเห็นว่าในส่วนที่เรียก method จะเปลี่ยน return type เป็น CompletableFuture\u0026lt;T\u0026gt; แทนครับ และจะมีโค้ดเพิ่มขึ้นมาคือ CompletableFuture.allOf(\u0026lt;async method\u0026gt;) ซึ่งจะทำหน้าที่เรียกและรอ return future value ให้เราจนกว่า async method ที่เรียกข้างในทำงานเสร็จทั้งหมดครับ ซึ่งหลังจากนั้นเราสามารถใช้ method get() เรียก CompletableFuture เพื่อดึงค่าออกมาจาก async method ได้เลย\nแต่ถ้าเราเรียกตอนนี้จะเห็นว่ามันยังเรียกแต่ละ method แบบ sychronous กันอยู่ทำให้ใช้เวลารวมทั้งหมดอยู่ 3 วิ (ถ้าแต่ละ method ใช้ 1 วิ) ซึ่งเกิดจากการที่ Executor ของเรายังเป็น applicationTaskExecutor ซึ่งรันอยู่บน single thread อยู่ครับ โดยเราสามารถเปลี่ยนไปใช้ Executor แบบ Async โดยการเพิ่ม Async Config ตามตัวอย่างข้างล่างได้ครับ\n@Configuration @EnableAsync public class AsyncConfig { @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); return executor; } } ซึ่งพอถึงจุดนี้ใน Service ของเราก็จะทำงานผ่าน asyncExecutor แล้วครับ แต่ถ้าเราสั่งให้ controller เราทำงานจะเห็นว่ามันยังทำงานอยู่ที่ 3 วิ อยู่ ทำไมมันยังไม่เร็วขึ้นนะ?\ncorePoolSize vs maxPoolSize สาเหตุที่มันยังทำงานแบบ synchronous อยู่ทั้งๆ ที่เราใช้ asyncExecutor เป็นเพราะว่ามันยังใช้ Thread เดียวอยู่ครับ ซึ่งถ้าเราไปดู Implementation ของ ThreadPoolTaskExecutor จะเห็นว่าเซต corePoolSize อยู่ที่ 1 เลยทำให้มันเป็น single thread แต่เราสามารถเพิ่มจำนวน thread ที่ stand by อยู่ได้ผ่าน method: setCorePoolSize ได้ โดยในที่นี้จะเซตเป็น 3 เท่าจำนวน tasks ที่เราจะแยก Thread ออกสูงสุดครับ\nCOPY\n@Configuration @EnableAsync public class AsyncConfig { @Bean public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(5); return executor; } } อีกส่วนคือ maxPoolSize ซึ่งเป็นตัวกำหนดว่า Java จะแตก Thread ได้มากที่สุดกี่ตัวครับ ซึ่ง default จะเป็นเท่ากับจำนวน Integer เลย ซึ่งเราควรจะกำหนดไว้เพื่อกันไม่ให้ Java แตก Thread ออกมามากเกินไปครับ ในที่นี้จะกำหนดเป็น 5\nซึ่งพอถึงจุดนี้ตัว Controller นี้จะทำงานอยู่ที่ประมาณ 1 วิ + นิดหน่อยครับ แล้วถ้าเราดูที่ service ปลายทางได้เราจะเห็นว่ามันยิง HTTP Request ออกมาแทบจะเวลาเดียวกันแล้วครับ\nReference เริ่มที่บล็อกนี้ได้ จะพาทัวร์ CompletableFuture API แบบง่ายๆ แต่ถ้าพูดถึง Thread Pool ไว้สั้นมาก จนอาจจะเผลอเลื่อนเลยไป https://medium.com/sipios/how-to-make-parallel-calls-in-java-springboot-application-and-how-to-test-them-dcc27318a0cf บล็อกนี้พาทัวร์ CompletableFutureAPI แบบ Advance กว่าลิ้งค์ข้างบน https://www.baeldung.com/java-completablefuture บล็อกนี้จะคล้ายๆ ลิ้งค์แรก แต่มีสิ่งที่เลอค่าตรง Limitation ของ @Async ที่สองบล็อกก่อนหน้าไม่ได้พูดถึง https://www.baeldung.com/spring-async บล็อกนี้พาไปทัวร์ Future API (เข้าใจว่าโบราณกว่า CompletableFuture) แต่จุดที่น่าสนใจคือพาเรามารู้จัก Thread Pools นี่แหละ https://www.baeldung.com/java-future บล็อกนี้อธิบายว่าเราควรเลือกใช้ corePoolSize กับ maxPoolSize ยังไง https://www.baeldung.com/java-threadpooltaskexecutor-core-vs-max-poolsize ","permalink":"https://yothinix-com.pages.dev/spring-kerwaid-maaeriiyk-method-ain-spring-aebb-parallel-dwy-async-kaneth-a/","summary":"\u003cp\u003eสมมติว่าเรามีโจทย์ที่ต้องยิง HTTP Request เพื่อดึง resource มาจาก Web service อื่นหลายๆ ที่ ถ้าเราไม่คิดอะไรเราก็อาจจะเขียนโค้ดให้ ยิงทีละตัวแบบ Synchronous ไปได้ แต่ถ้าแต่ละ Request ไม่ได้ขึ้นต่อกัน เราจะมีตัวเลือกมากขึ้นผ่านการยิงแบบ Asynchronous ครับ ซึ่งผมเพิ่งรู้ว่า Java มันทำได้\u003c/p\u003e\n\u003ch2 id=\"example\"\u003e\u003cstrong\u003eExample\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eสมมติว่าเรามี Service ที่ไว้ยิง HTTP Request ไปที่ API อื่นแบบง่ายๆ หน้าตาประมาณนี้\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nd\"\u003e@Service\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eActivityService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"n\"\u003eRestTemplate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erestTemplate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRestTemplate\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eResponseSecond\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003egetEndpointOne\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;http://localhost:8000/1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eResponseSecond\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erestTemplate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetForObject\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eResponseSecond\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eและมี Controller ที่เรียกใช้ Service นี้หน้าตาประมาณนี้\u003c/p\u003e","title":"Spring ก็เร็วได้! มาเรียก Method ใน Spring แบบ Parallel ด้วย @Async กันเถอะ"},{"content":"ขอรีวิวคลาส \u0026ldquo;Domain Driven Design แบบรูฟๆ\u0026rdquo; หน่อยนะครับ เป็นการขอบคุณที่พี่รูฟ Twin Panitsombat มอบดาบให้ไปสู้กับไฮดรา (หรือไปสร้างไฮดราตัวใหม่นะ)\n\u0026ldquo;คนที่มาเรียนถ้าไม่มาเรียนเพื่อแสวงหาความรู้ ก็มาเรียนรู้เพื่ออธิบายสิ่งที่ตัวเองทำเป็นธรรมชาติอยู่แล้ว\u0026rdquo;\nผมเริ่มค้นพบอย่างนึงว่า ผมชอบฟังเรื่องราวที่คนทำ Software ในยุคก่อนผมเข้าวงการ เค้าเจออะไร แล้วแก้ปัญหาอะไรมาก มันเหมือนกับการที่เราพยายามกลับไปทำความเข้าใจรากของปัญหาว่า ก่อนจะมาถึงทุกวันนี้ วงการนี้มันผ่านอะไรมาบ้าง แล้วภาพที่พี่รูฟ เล่าตั้งแต่ Software Crisis มันเหมือน Connect the dot ที่ผมรู้มาตลอดชีวิตเข้าด้วยกันตั้งแต่ XP, Scrum และ Kanban และช่องว่างตรงกลางที่ผมรู้สึกมาซักพักใหญ่มาก แต่ไม่รู้ว่ามันคืออะไร จนมาได้คำตอบว่ามันคือ Domain Driven Design ครับ\nคลาสนี้รู้สึกว่าได้เครื่องมือมาหลากหลายมาก ที่บอก How ในการทำ Architecture design ที่ตลอดชีวิตมา เริ่มด้วย Data model ก่อนเสมอ ตั้งแต่การ define space อย่าง Problem space กับ Solution space ซึ่ง ตอนจังหวะนี้ประสบการณ์ Scrum มาตลอดชีวิตภาพมันกลับมาทั้ง Sprint Planning, Refinement แต่ที่ surprise ตัวเองมากคือภาพตอนเรียน Category Theory ไม่กี่สัปดาห์ก่อนมันกลับมาด้วย และมันกลับมาบ่อยมากๆ ตลอดเวลาที่เหลือของ class DDD วันนี้ทั้งภาพ Domain, Co Domain, Functor, Object, Morphism, Category of Type ตอนทำ Workshop ทำ Context Mapping และหา Event Sourcing กับ CQRS และอื่นๆ อีกหลายจุดครับ เรียกได้ว่าหลอกหลอนมาก 555\nซึ่งทั้งหลายทั้งมวลที่เรียนวันนี้ ส่วนตัวเข้าใจว่า พยายามตอบโจทย์ที่จะทำยังไงก็ได้ให้ Architecture ของเรามัน Emergent design ได้ต่อๆ ไปด้วย แต่สิ่งที่ผมได้มามากที่สุดน่าจะเป็นการดึง Domain Knowledge ออกมาจาก Expert (ซึ่งไม่ใช่เราชาว Software Engineer แน่ๆ) แต่เป็นคนที่อยู่หน้างานตรงนั้น และสร้าง Software ที่มันสะท้อนกับสิ่งที่ลูกค้าเป็นมากที่สุด โดยการมอบตัวเลือกต่างๆ ให้เค้าตัดสินใจ และตอบคำถามสำคัญมากคือ \u0026ldquo;ทำอะไรก่อน\u0026rdquo; และ \u0026ldquo;เรามีบุญพอจะทำไหวมั้ย\u0026rdquo;\nสุดท้ายต้องบอกว่า ถึงแม้ผมจะพยายามศึกษาเรื่องนี้เองรวมถึงมี Blue book ไว้บูชาที่ห้องมามาหลายปี ก็ต้องบอกว่า ของบางอย่าง มันต้องรู้ในเวลาที่ใช่จริงๆ เราถึงจะเข้าใจคุณค่าของมันครับ ต้องกราบขอบคุณพี่รูฟอีกครั้งที่เปิดคลาสนี้ให้เรียน หวังว่าซักวันคงจะมีโอกาสได้เรียนครึ่งหลังของคลาสนี้จริงๆ 🙏\n","permalink":"https://yothinix-com.pages.dev/domain-driven-design/","summary":"\u003cp\u003eขอรีวิวคลาส \u0026ldquo;Domain Driven Design แบบรูฟๆ\u0026rdquo; หน่อยนะครับ เป็นการขอบคุณที่พี่รูฟ \u003ca href=\"https://www.facebook.com/roofimon.class\"\u003eTwin Panitsombat\u003c/a\u003e มอบดาบให้ไปสู้กับไฮดรา (หรือไปสร้างไฮดราตัวใหม่นะ)\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;คนที่มาเรียนถ้าไม่มาเรียนเพื่อแสวงหาความรู้ ก็มาเรียนรู้เพื่ออธิบายสิ่งที่ตัวเองทำเป็นธรรมชาติอยู่แล้ว\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eผมเริ่มค้นพบอย่างนึงว่า ผมชอบฟังเรื่องราวที่คนทำ Software ในยุคก่อนผมเข้าวงการ เค้าเจออะไร แล้วแก้ปัญหาอะไรมาก มันเหมือนกับการที่เราพยายามกลับไปทำความเข้าใจรากของปัญหาว่า ก่อนจะมาถึงทุกวันนี้ วงการนี้มันผ่านอะไรมาบ้าง แล้วภาพที่พี่รูฟ เล่าตั้งแต่ Software Crisis มันเหมือน Connect the dot ที่ผมรู้มาตลอดชีวิตเข้าด้วยกันตั้งแต่ XP, Scrum และ Kanban และช่องว่างตรงกลางที่ผมรู้สึกมาซักพักใหญ่มาก แต่ไม่รู้ว่ามันคืออะไร จนมาได้คำตอบว่ามันคือ Domain Driven Design ครับ\u003c/p\u003e\n\u003cp\u003eคลาสนี้รู้สึกว่าได้เครื่องมือมาหลากหลายมาก ที่บอก How ในการทำ Architecture design ที่ตลอดชีวิตมา เริ่มด้วย Data model ก่อนเสมอ ตั้งแต่การ define space อย่าง Problem space กับ Solution space ซึ่ง ตอนจังหวะนี้ประสบการณ์ Scrum มาตลอดชีวิตภาพมันกลับมาทั้ง Sprint Planning, Refinement แต่ที่ surprise ตัวเองมากคือภาพตอนเรียน Category Theory ไม่กี่สัปดาห์ก่อนมันกลับมาด้วย และมันกลับมาบ่อยมากๆ ตลอดเวลาที่เหลือของ class DDD วันนี้ทั้งภาพ Domain, Co Domain, Functor, Object, Morphism, Category of Type ตอนทำ Workshop ทำ Context Mapping และหา Event Sourcing กับ CQRS และอื่นๆ อีกหลายจุดครับ เรียกได้ว่าหลอกหลอนมาก 555\u003c/p\u003e","title":"รีวิวคลาส Domain Driven Design แบบ รูฟๆ"},{"content":"Story 2 - 3 วันที่ผ่านมาพยายามต่อ Redis บน ElastiCache แล้ว Error ตลอดเวลาเรียกใช้ จะมี Log ขึ้นประมาณข้างล่างนี้ แล้วแก้จนมันใช้ได้แล้วเอาขึ้น Server ไปละ นี่คือเรื่องของมัน\norg.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to ███████-cache.███████.com:6379 Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to ███████-cache.███████.com:6379 e Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching ███████-cache.███████.com found. สันนิษฐานแรกคือน่าจะเกี่ยวกับ In-Transit Encryption feature ของ ElastiCache\u0026rsquo;s Redis ซึ่งถูกเลือกไว้แล้ว แล้วหลังจาก Research ไปซักระยะเลยเจอว่า ElastiCache\u0026rsquo;s Redis allow ให้ Connect ผ่าน VPC เท่านั้น\nAmazon ElastiCache Nodes, deployed within a VPC, can never be accessed from the Internet or from EC2 Instances outside the VPC. Source\nระหว่างนั้นเลยไปทดลองสร้างเครื่อง EC2 ในวง VPC เดียวกันมา Connect แต่ก็เจอปัญหา Error: Connection reset by peer เวลาต่อจาก redis-cli ที่วิ่งอยู่บน Stunnel แล้ว ซึ่งแก้เท่าไรก็ยังไม่ได้ และไม่ได้เกี่ยวกับ IAM Role ด้วยเพราะลอง FullAccessElastiCache ก็ยังไม่ได้\nสุดท้ายพี่กานต์ลองใช้ Python Redis client ยิงดูปรากฏว่าติด หน้าตาโค้ดประมาณนี้ เลยรู้สึกว่าไม่ใช่ละ\nimport redis r = redis.Redis(host=\u0026#39;███████-cache.███████.com\u0026#39;, port=6379, db=0, ssl=True) r.set(\u0026#39;foo\u0026#39;, \u0026#39;bar\u0026#39;) print(r.get(\u0026#39;foo\u0026#39;)) ซึ่งมีจุดที่ remind อย่างนึงคือ ssl=True เลยพุ่งเป้ากลับมาที่เรื่อง SSL Certificate น่าจะมีปัญหาอะไรบางอย่าง หลังจากนั้นพยายามลองเซต spring.redis.ssl=true ใน application.properties ก็ยังไม่ได้ขึ้น Exception เหมือนตอนแรก ก็เลยมานั่งมอง Exception ละเอียดๆ อีกทีจนไปสะดุดตาอันสุดท้าย\nCaused by: java.security.cert.CertificateException: No subject alternative DNS name matching ███████-cache.███████.com found. Search ไปๆ มาๆ เลยมาเจอบล็อกนี้ [Solved] java.security.cert.CertificateException: No subject alternative names present ใจความหลักๆ เหมือนกันคือต่อ LDAP ไม่ได้ เพราะ Java 1.8.0_181 เปิด \u0026ldquo;Endpoint identification\u0026rdquo; เป็น default เพื่อให้ใช้กับ LDAPS connection ได้ ซึ่งก็มีวิธีปิดอยู่ง่ายๆ คือไปเพิ่ม property ข้างล่างก็ได้ละ\n-Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true ซึ่งถึงแม้มันจะไม่ได้แก้ปัญหาของ ElastiCache ต่อไม่ได้ตรงๆ แต่ได้ keyword สำคัญมากคือ disableEndpointIdentification ลิ้งค์ต่อๆ มาเลยยังพุ่งเป้าไปที่เรื่องนี้อยู่ แล้วมาเจอกับ issues นี้ใน github CertificateException while connecting to Azure redis cluster. #1296 ซึ่งเจอกับ Redis เต็มๆ แต่เป็น Azure แต่ที่สำคัญคือ อันนี้เป็นปัญหาบน Library: Redisson ซึ่งเป็น Redis Java Client เหมือนกัน และก็ยิ่งย้ำความเชื่อว่ามันเป็นเรื่อง EndpointIdentification นี่แหละ\nณ จุดนี้คือกลับมานั่งทำความเข้าใจอีกทีว่า spring-data-redis ใช้อะไรอยู่ข้างล่าง จาก Official Document เลยค้นพบว่าข้างล่างมันใช้ Lettuce เป็น Client อยู่ เลยมาเจอ issue Lettuce can\u0026rsquo;t connect to Redis Cluster + SSL but can connect to same Redis server + SSL if treated as Standalone node. #1454 ซึ่งคำตอบแรกของ issue นี้ คือคำตอบเลย\nThere are a couple of things you can do about:\nIf the Redis IP addresses can be mapped onto a hostname, then please configure a MappingSocketAddressResolver through ClientResources to map IP addresses into hostnames that are listed in the SSL certificate Reach out to the Azure support team so that they fix the SSL certificates and include all cluster IP addresses (least favorable option) Disable SSL certificate validation. That can be done with RedisURI.setVerifyPeer(false) when using Lettuce directly. For Spring, you should be able to register a LettuceClientConfigurationBuilder customizer to invoke LettuceSslClientConfigurationBuilder.disablePeerVerification(). ซึ่งทำให้เราได้คีย์เวิร์คสำคัญมาคือ disablePeerVerification (มันต้องเหมือนข้างบนแน่ๆ) คำถามถัดมาคือ เราจะ disable มันยังไงใน Spring เลยต้องไปหาวิธีใช้ LettuceSslClientConfigurationBuilder อยู่ซักพักใหญ่ๆ เลย ซึ่งอ่าน Doc เฉยๆ ก็เขียนยังไม่เป็นด้วยประสบการณ์ Java แค่นี้\nสุดท้ายเลยไปเริ่มจากตัวอย่างของ repository นี้ spring-data-redis-lettuce ซึ่งยกตัวอย่าง custom LettuceConnectionFactory ไว้ได้โอเคเลย แล้วทำให้เริ่มจากตรงนี้จนมาเป็น ลองผิดลองถูก อ่าน Document ของ LettuceClientConfigurationBuilder จนได้โค้ดของ configuration ข้างล่างนี้\nimport org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.StringRedisTemplate; @Configuration public class RedisClientConfig { @Value(\u0026#34;${spring.redis.host}\u0026#34;) private String redisHost; @Value(\u0026#34;${spring.redis.port}\u0026#34;) private int redisPort; @Bean public StringRedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { final StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(lettuceConnectionFactory); return template; } @Bean LettuceConnectionFactory lettuceConnectionFactory() { LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder() .useSsl() .disablePeerVerification() .build(); RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration(redisHost, redisPort); return new LettuceConnectionFactory(serverConfig, clientConfig); } } แล้วใน application.properties จะเหลือแค่\nspring.cache.type=redis spring.redis.host=███████-cache.███████.com spring.redis.port=6379 spring.cache.redis.time-to-live=18000 Resources Official documentation ของ AWS ใช้ต่อ Redis ใน ElastiCache Connect to a Cluster\u0026rsquo;s Node a.k.a. วิธี Build redis-cli ElastiCache for Redis In-Transit Encryption (TLS) a.k.a. วิธีเซต Stunnel How do I connect to an Amazon ElastiCache In-Transit encryption-enabled Redis node using redis-cli? a.k.a. วิธีเซต Stunnel สองบล็อกนี้แนะนำให้ไปใช้ stunnel วิธีเดียวกับ AWS Official ถ้าจะต่อเข้าไป Redis ใน ElastiCache Making a secure connection to ElastiCache (Redis) How to Fix Redis CLI Error Connection Reset by Peer Example how to config RedisConnectionFactory (link) Spring Official Document: Configuring the Lettuce Connector (link) Lettuce can\u0026rsquo;t connect to Redis Cluster + SSL but can connect to same Redis server + SSL if treated as Standalone node. #1454 a.k.a. Issue ที่เป็นคำตอบ spring-data-redis-lettuce a.k.a. ตัวอย่าง Implement Custom LettuceConnection Lettuce Host/Peer Verification a.k.a. วิธีใช้ Builder กับ Peer verification Lettuce SSL มาจากตรงนี้ก่อน ","permalink":"https://yothinix-com.pages.dev/spring-boot-with-aws-elasticache/","summary":"\u003ch2 id=\"story\"\u003e\u003cstrong\u003eStory\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e2 - 3 วันที่ผ่านมาพยายามต่อ Redis บน ElastiCache แล้ว Error ตลอดเวลาเรียกใช้ จะมี Log ขึ้นประมาณข้างล่างนี้ แล้วแก้จนมันใช้ได้แล้วเอาขึ้น Server ไปละ นี่คือเรื่องของมัน\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eorg\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003espringframework\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eredis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eRedisConnectionFailureException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003econnect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRedis\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enested\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexception\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003elettuce\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecore\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eRedisConnectionException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003econnect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003ecache\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecom\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003e6379\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCaused\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eby\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003elettuce\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecore\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eRedisConnectionException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003econnect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003ecache\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecom\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"n\"\u003e6379\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCaused\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eby\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejavax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003enet\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003essl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eSSLHandshakeException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGeneral\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSSLEngine\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproblem\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCaused\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eby\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejavax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003enet\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003essl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eSSLHandshakeException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGeneral\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSSLEngine\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproblem\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCaused\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eby\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejava\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003esecurity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecert\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eCertificateException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esubject\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealternative\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDNS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ematching\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003ecache\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"err\"\u003e███████\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ecom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efound\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eสันนิษฐานแรกคือน่าจะเกี่ยวกับ In-Transit Encryption feature ของ ElastiCache\u0026rsquo;s Redis ซึ่งถูกเลือกไว้แล้ว แล้วหลังจาก Research ไปซักระยะเลยเจอว่า ElastiCache\u0026rsquo;s Redis allow ให้ Connect ผ่าน VPC เท่านั้น\u003c/p\u003e","title":"แชร์ประสบการณ์ Config ตัว Amazon ElastiCache ให้ใช้งานกับ Spring Boot"},{"content":"อยากจะพูดถึงคอร์ส Mathematics for Working Programmers ของอาจารย์เดฟ Dave Rawitat Pulam ที่เพิ่งรอดกลับมาหลังจาก 2 วันที่หนักหน่วงหน่อยครับ\n\u0026ldquo;ทำไมต้อง Refactor ถ้าเรา Prefactoring ได้ตั้งแต่แรก\u0026rdquo;\nนั่นคือประโยคที่ผมชอบที่สุดตลอดสองวันที่ผ่านมา ต้องบอกว่าก่อนไปเรียนคือ ผมไม่รู้เลยว่าจะไปเจอกับอะไรบ้าง แต่ก็มั่นใจระดับนึงว่าประสบการณ์เขียนโปรแกรมที่มีมันน่าจะพาเราเอาตัวรอดไปได้ระดับนึงละ พอผ่านไปไม่กี่สไลด์เท่านั้นแหละผมคิดผิด และผมเลยเพิ่งรู้ตัวเลยว่าผมมองโลกผ่านรูกุญแจมาตลอด อารมณ์เหมือน Dr.Strange เจอ Ancient One ครั้งแรกเลย\nเบิกเนตรแรกเลยคือ ผมไม่เคยรู้จัก State machine, Turing Machine ฯลฯ อะไรเลย แต่มารู้ในคอร์สนี้แหละว่าสิ่งนี้มันกำหนดวิธีมองโลก (ผ่านรูกุญแจ) ของผมมาตลอดหลายๆ ปีเลย ได้รู้จักคณิตศาสตร์ในมุมที่มันสวยงาม ไม่ใช่แรงงาน เหมือนกลับไปอ่านเรื่องราวของพอล แอร์ดิชกับรามานุจัน อีกครั้ง แต่ในขณะที่ตื่นตากับการเบิกเนตรครั้งที่หนึ่งและรู้สึกว่าการรู้สิ่งนี้จะทำให้เราเข้าใจโลกมากขึ้น อาจารย์เดฟก็เขย่าโลกครั้งที่สองครับด้วย lambda calculus\nเบิกเนตรครั้งที่สองพาผมย้อนกลับไปรู้จักกับความเรียบง่ายของ Function อีกครั้งที่เคยเรียนเมื่อเกิน 10 ปีที่แล้ววิธีคิด และค่อยๆ ไต่ระดับไปจนถึงจุดที่มัน \u0026ldquo;Equivalent\u0026rdquo; กันซึ่งคลาสนี้มันจะมีหลายจุดมากๆ ที่ระหว่างเรียนเราต้องสู้กับจิตใจตัวเองในการ unlearn ความเข้าใจที่เราเข้าใจมาตลอดหลายๆ ปี ซึ่งบางจุดก็ง่าย แต่บางจุดนั้นมันก็ยากจริงๆ ครับแต่ eventually เราจะเข้าใจมันเอง\nจุดที่ผมประทับใจมากอีกจุดนึงคือเรื่อง Type ครับ ตลอดชีวิตการเขียนโปรแกรมมาหลายปี หนังสือไม่รู้กี่เล่ม Talk ไม่รู้กี่ตัว ไม่เคยมีใครเล่าเรื่อง Type ได้เห็นภาพขนาดนี้และผมจะรู้สึกผิดมากถ้าผมมาเล่าสปอยไว้ตรงนี้ เพราะอยากให้คนอื่นได้ฟังจากในคอร์สนี้เองจริงๆ\nเบิกเนตรตัวสุดท้ายที่อยากพูดถึงในคอร์สนี้คือ Category Theory, Monad, Monoid, Functor และคณะนั่นแหละครับ เป็นสิ่งที่ผมรู้จักแต่ชื่อและไม่กล้าจะทำความรู้จักมันมาหลายปี แต่หลังจากคอร์สนี้ถึงแม้ผมจะพูดได้ไม่เต็มปากเลยว่าผมเข้าใจมัน แต่พอผ่านจุดที่อาจารย์เดฟเล่าให้ฟังมาได้มันเป็นเหมือนเชื้อเพลิงให้ไปศึกษาเองต่อได้อีกเยอะเลยครับ (และแน่นนอนครับว่าโดนป้ายยาหนังสือมาหลายเล่มมากจากคอร์สนี้)\nอ่อ สิ่งที่เหลือเชื่ออย่างนึงของคลาสนี้คือพลังของมันครับ มันเป็นการเรียนตั้งแต่เก้าโมงครึ่งถึงทุ่มนิดๆ หยุดพักแค่ตอนกินข้าวเที่ยงแปปนึง ความเหลือเชื่อที่ลากตัวเองเรียนจนจบในแต่ละวันไปได้แล้ว (พร้อมกลับบ้านด้วยความหิวโหยเหมือนไปวิ่งรอบสนามบอลมาเป็นสิบๆ รอบ) ยังเหลือเชื่อในพลังของอาจารย์เดฟที่ไม่ตกตั้งแต่นาทีแรกจนถึงนาทีสุดท้ายของคอร์สเลยครับ\nสุดท้ายต้องบอกว่านี่เป็นคอร์สที่เราทุกคน ควรเรียนซักครั้งในชีวิตครับ เพราะประตูที่คลาสนี้เปิดออกให้เราดูโลกมันกว้างมากจนเอาไปใช้ได้มากกว่าแค่เขียนโปรแกรมเลยในชีวิต และผมบอกได้เลยว่า ผมจินตนาการไม่ออกเลยว่าจะมีใครเปิดประตูนี้ให้เราได้ดีไปกว่าอาจารย์เดฟกับคอร์สนี้ครับ\n","permalink":"https://yothinix-com.pages.dev/math-for-working-programmer/","summary":"\u003cp\u003eอยากจะพูดถึงคอร์ส Mathematics for Working Programmers ของอาจารย์เดฟ Dave Rawitat Pulam ที่เพิ่งรอดกลับมาหลังจาก 2 วันที่หนักหน่วงหน่อยครับ\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;ทำไมต้อง Refactor ถ้าเรา Prefactoring ได้ตั้งแต่แรก\u0026rdquo;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eนั่นคือประโยคที่ผมชอบที่สุดตลอดสองวันที่ผ่านมา ต้องบอกว่าก่อนไปเรียนคือ ผมไม่รู้เลยว่าจะไปเจอกับอะไรบ้าง แต่ก็มั่นใจระดับนึงว่าประสบการณ์เขียนโปรแกรมที่มีมันน่าจะพาเราเอาตัวรอดไปได้ระดับนึงละ พอผ่านไปไม่กี่สไลด์เท่านั้นแหละผมคิดผิด และผมเลยเพิ่งรู้ตัวเลยว่าผมมองโลกผ่านรูกุญแจมาตลอด อารมณ์เหมือน Dr.Strange เจอ Ancient One ครั้งแรกเลย\u003c/p\u003e\n\u003cp\u003eเบิกเนตรแรกเลยคือ ผมไม่เคยรู้จัก State machine, Turing Machine ฯลฯ อะไรเลย แต่มารู้ในคอร์สนี้แหละว่าสิ่งนี้มันกำหนดวิธีมองโลก (ผ่านรูกุญแจ) ของผมมาตลอดหลายๆ ปีเลย ได้รู้จักคณิตศาสตร์ในมุมที่มันสวยงาม ไม่ใช่แรงงาน เหมือนกลับไปอ่านเรื่องราวของพอล แอร์ดิชกับรามานุจัน อีกครั้ง แต่ในขณะที่ตื่นตากับการเบิกเนตรครั้งที่หนึ่งและรู้สึกว่าการรู้สิ่งนี้จะทำให้เราเข้าใจโลกมากขึ้น อาจารย์เดฟก็เขย่าโลกครั้งที่สองครับด้วย lambda calculus\u003c/p\u003e\n\u003cp\u003eเบิกเนตรครั้งที่สองพาผมย้อนกลับไปรู้จักกับความเรียบง่ายของ Function อีกครั้งที่เคยเรียนเมื่อเกิน 10 ปีที่แล้ววิธีคิด และค่อยๆ ไต่ระดับไปจนถึงจุดที่มัน \u0026ldquo;Equivalent\u0026rdquo; กันซึ่งคลาสนี้มันจะมีหลายจุดมากๆ ที่ระหว่างเรียนเราต้องสู้กับจิตใจตัวเองในการ unlearn ความเข้าใจที่เราเข้าใจมาตลอดหลายๆ ปี ซึ่งบางจุดก็ง่าย แต่บางจุดนั้นมันก็ยากจริงๆ ครับแต่ eventually เราจะเข้าใจมันเอง\u003c/p\u003e\n\u003cp\u003eจุดที่ผมประทับใจมากอีกจุดนึงคือเรื่อง Type ครับ ตลอดชีวิตการเขียนโปรแกรมมาหลายปี หนังสือไม่รู้กี่เล่ม Talk ไม่รู้กี่ตัว ไม่เคยมีใครเล่าเรื่อง Type ได้เห็นภาพขนาดนี้และผมจะรู้สึกผิดมากถ้าผมมาเล่าสปอยไว้ตรงนี้ เพราะอยากให้คนอื่นได้ฟังจากในคอร์สนี้เองจริงๆ\u003c/p\u003e","title":"รีวิวคอร์ส Mathematics for Working Programmers"},{"content":"เคยมั้ยครับ เวลาเรา Discussion ในทีมเกี่ยวกับวิธี Implementation ของฟีเจอร์หนึ่งๆ แล้วเราหรือแม้แต่คนอื่นในทีมจะมีโมเม้นต์ประมาณว่า “กับฟีเจอร์นี้นะ เราเคยทำแบบนี้ A B C D นะ ต้องทำอย่างนี้สิ เราเคยทำมาแล้วมันเวิร์ค” แล้วหลังจากนั้นทีมก็ตกลงทำฟีเจอร์ด้วยวิธีนี้แล้วผ่านไปก็ค้นพบว่า ทำไมพอจะทำอะไรๆ ต่อมันยากไปหมดนะ\nรู้จักกับ Second-System Effect สถานการณ์แบบที่กล่าวมาข้างต้นนั้น ไม่ใช่เรื่องใหม่ครับและ ไม่ใช่เรื่องใหม่ในวงการ Software ด้วย ย้อนไปในปี 1975 Fred Brooks ได้พูดถึง Second-System Effect ไว้ในหนังสือ The Mythical Man-Month ว่า\nงานแรกของ Architect มักจะค่อนข้างกั๊ก เค้าจะรู้ตัวว่าเค้าไม่รู้อะไรบ้างในงานที่เค้าทำ เลยทำให้เค้ามีความระวังค่อนข้างมากเป็นพิเศษ\nระหว่างที่เค้า Design งานตัวเองไป เค้าจะค้นพบท่าใหม่ๆ ทีละเล็ก ทีละน้อยแต่ก็จะยังไม่เอามาใช้เต็มที่และเก็บเอาไว้ใช้ “คราวหน้า” ผ่านไปไม่นาน ระบบแรกก็จะเสร็จและ Architect ที่เต็มไปด้วยความภูมิใจและมั่นใจในการสร้างระบบก็พร้อมที่จะสร้างระบบที่สองละ\nระบบที่สองที่ Architect ออกแบบจะเป็นระบบที่อันตรายที่สุดที่เค้าเคยออกแบบ เมื่อเค้าออกแบบระบบที่ 3 และต่อๆ ไป ประสบการณ์ก่อนหน้านั้นจะช่วยยืนยันตัวเองว่า ระบบหนึ่งๆ นั้นมีความแตกต่างกันในแต่ละส่วนและไม่สามารถที่จะทำให้เหมือนกันได้\nซึ่งหลายๆ ครั้งพอเป็นระบบแนวๆ ที่เราเคยทำมาแล้ว เราก็มักจะเลือกวิธีที่เราเคยทำใช่มั้ยครับ เพราะเรารู้รายละเอียดที่สุด แต่ต้องระวังว่า ในความเหมือนนั้น มันก็จะมีความแตกต่างอยู่ และหลายๆ ครั้งเรามักจะ Over Design เกินกว่าความเป็นจริงไปโดยไม่รู้ตัว\nเราจะหลีกเลี่ยง Second-System Effect ได้ยังไง แน่นอนครับว่า ถ้าเราเป็น Architect เราหนีไม่พ้นแน่ๆ ที่จะต้อง Design ระบบที่ 2 (คงไม่มีใคร Design โปรเจ็คแรกเสร็จแล้วเปลี่ยนไปทำงานอย่างอื่นหรอก ใช่มั้ยนะ)\nในหนังสือแนะนำประมาณว่า ให้เราพยายามมีสติเวลาเจอกับความประหลาดๆ ของ requirement ของระบบ พยายามมีวินัยไม่ลองท่าแปลกๆ มากเกินไป หลีกเลี่ยงการบิด requirement เพื่อให้เข้ากับท่าที่เราอยากลองหรือเคยทำ\nแต่ท่าที่ผมชอบที่สุดคือ การให้คุณค่าของฟังก์ชั่นหนึ่งๆ ครับ โดยให้ ความสามารถของฟังก์ชั่นเป็น x ที่ไม่มากไปว่า m bytes ของหน่วยความจำและจำนวนการเรียกใช้ที่ n microseconds ครับ ซึ่งมันคือการวัดจริงๆ เลยว่าของที่เราทำมันมีคุณค่าจริงๆ แบบจับต้องได้ครับ\nนอกจากนี้ยังมีท่าแนะนำให้ Project Manager ป้องกัน Second-System effect จาก Architect ในทีมด้วยนะครับ โดยให้พยายามระวัง design ที่มันมีความต้องการแปลกๆ หรือคุณ PM นี่อาจจะถามคำถามเพิ่มเพื่อให้เข้าใจไอเดียที่อยู่เบื้องหลัง design ก็ได้เพื่อเช็คว่า design นั้นเนี่ยถูกออกแบบมาเพื่อตอบโจทย์ที่ต้องการจริงๆ โดยไม่มี Hidden Agenda อยู่เบื้องหลัง\nYAGNI อีกวิธีที่จะช่วยป้องกัน Second-System Effect ได้คือ You Arent Gonna Need It หรือ YAGNI ครับ ซึ่งเป็น Practice มาจากฝั่ง Extreme Programming ซึ่งตามประโยคเต็มๆ ครับ หรือจะนิยามสั้นๆ ว่า\nจงทำสิ่งที่จำเป็นในเวลาที่จำเป็น ไม่ใช่ตอนที่คิดว่าจะเป็น\nซึ่งนี่เป็นวิธีการตั้งคำถามที่ฉลาดมากครับ เพราะหลายๆ ครั้งในชีวิตการออกแบบโปรแกรมเรา เรามักจะ “เผื่อ”​ ไปหาอนาคตว่า นี่แหละมันต้องใช้แน่ๆ แต่หลายๆ ครั้งพอถึงเวลาจริงๆ เราอาจจะไปอีกทางเลยก็ได้ครับ ซึ่งเหตุผลหลักที่เราควรตั้งคำถาม YAGNI กับงานที่เราทำบ่อยๆ คือมันช่วยให้เรา โค้ดเราสะอาดและประหยัดเวลาที่จะเขียนโค้ดที่ไม่จำเป็นที่จะไม่ได้ใช้ในอนาคตไปได้เยอะเลยครับ\nส่วนตัวผมเคยมีประสบการณ์นี้แบบจำได้แม่นๆ เมื่อหลายปีก่อนครับ ผมเป็นคนเชื่อมันใน Asynchronous Queue/Worker มากว่ามันตอบโจทย์หลายๆ อย่าง ซึ่งระบบแรกที่ผมทำ ตัว Asynchronous Queue เราค่อนข้างจะเอาอยู่ว่ามันจะเกิดอะไรขึ้นบ้าง แล้วช่วยให้ Performance โดยรวมของระบบดีขึ้นยังไง\nพอถึงระบบที่สองที่ผมเริ่มประยุกต์เอา Asynchronous Queue มาใช้แรกๆ ก็เหมือนจะดีเอาอยู่ครับ แต่พอเวลาผ่านไปด้วย Nature ของระบบที่มันต่างกันทำให้ Async Queue เราเริ่มเอาไม่อยู่ ต้องใช้เวลา Processing หลายชั่วโมงจน Scale ไม่ทัน ไม่พร้อมรับ Usage Pattern แบบที่เจออยู่ จนต้องปวดหัวไปหลายเดือนในการ Optimize กับ Scaling ตัว Asynchronous Queue ตัวนี้ครับ\nซึ่งก็หวังว่าถ้าได้อ่านเรื่องนี้ หลายๆ คนน่าจะฉุกคิดและระลึกถึงประสบการณ์ตัวเองที่ผ่านมานะครับ หรือถ้าใครยังไม่มีโอกาส Design system การได้รู้จักเรื่องนี้พอถึงเวลาก็หวังว่ามันจะคอยช่วยเราไม่ให้ลงหลุมเหมือนที่ผมเจอนะครับ ใครเจอประสบการณ์ Second-System Effect มาแล้วก็ลองแบ่งปันกันดูครับ ผมอยากฟัง!\nOriginal post at: https://yothinix.medium.com/อย่าเผลอรัก-design-ตัวเอง-มาทำความรู้จักกับ-second-system-effect-กัน-543d1d26c5be\n","permalink":"https://yothinix-com.pages.dev/second-system-effect/","summary":"\u003cp\u003eเคยมั้ยครับ เวลาเรา Discussion ในทีมเกี่ยวกับวิธี Implementation ของฟีเจอร์หนึ่งๆ แล้วเราหรือแม้แต่คนอื่นในทีมจะมีโมเม้นต์ประมาณว่า “กับฟีเจอร์นี้นะ เราเคยทำแบบนี้ A B C D นะ ต้องทำอย่างนี้สิ เราเคยทำมาแล้วมันเวิร์ค” แล้วหลังจากนั้นทีมก็ตกลงทำฟีเจอร์ด้วยวิธีนี้แล้วผ่านไปก็ค้นพบว่า ทำไมพอจะทำอะไรๆ ต่อมันยากไปหมดนะ\u003c/p\u003e\n\u003ch1 id=\"รจกกบ-second-system-effect\"\u003eรู้จักกับ Second-System Effect\u003c/h1\u003e\n\u003cp\u003eสถานการณ์แบบที่กล่าวมาข้างต้นนั้น ไม่ใช่เรื่องใหม่ครับและ ไม่ใช่เรื่องใหม่ในวงการ Software ด้วย ย้อนไปในปี 1975 Fred Brooks ได้พูดถึง Second-System Effect ไว้ในหนังสือ The Mythical Man-Month ว่า\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eงานแรกของ Architect มักจะค่อนข้างกั๊ก เค้าจะรู้ตัวว่าเค้าไม่รู้อะไรบ้างในงานที่เค้าทำ เลยทำให้เค้ามีความระวังค่อนข้างมากเป็นพิเศษ\u003cbr\u003e\n\u003cbr\u003e\nระหว่างที่เค้า Design งานตัวเองไป เค้าจะค้นพบท่าใหม่ๆ ทีละเล็ก ทีละน้อยแต่ก็จะยังไม่เอามาใช้เต็มที่และเก็บเอาไว้ใช้ “คราวหน้า” ผ่านไปไม่นาน ระบบแรกก็จะเสร็จและ Architect ที่เต็มไปด้วยความภูมิใจและมั่นใจในการสร้างระบบก็พร้อมที่จะสร้างระบบที่สองละ\u003cbr\u003e\n\u003cbr\u003e\nระบบที่สองที่ Architect ออกแบบจะเป็นระบบที่อันตรายที่สุดที่เค้าเคยออกแบบ เมื่อเค้าออกแบบระบบที่ 3 และต่อๆ ไป ประสบการณ์ก่อนหน้านั้นจะช่วยยืนยันตัวเองว่า ระบบหนึ่งๆ นั้นมีความแตกต่างกันในแต่ละส่วนและไม่สามารถที่จะทำให้เหมือนกันได้\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eซึ่งหลายๆ ครั้งพอเป็นระบบแนวๆ ที่เราเคยทำมาแล้ว เราก็มักจะเลือกวิธีที่เราเคยทำใช่มั้ยครับ เพราะเรารู้รายละเอียดที่สุด แต่ต้องระวังว่า ในความเหมือนนั้น มันก็จะมีความแตกต่างอยู่ และหลายๆ ครั้งเรามักจะ Over Design เกินกว่าความเป็นจริงไปโดยไม่รู้ตัว\u003c/p\u003e","title":"อย่าเผลอรัก Design ตัวเอง มาทำความรู้จักกับ Second-System effect กัน"},{"content":"ในโลกที่วุ่นวาย และงานที่ถาโถม ทำให้ตลอดชีวิตที่ผ่านมา ไม่ทางใดก็ทางหนึ่ง ผมมักจะหาทางจัดการตัวเองผ่านอะไรซักอย่าง ซึ่งอาจจะเป็นได้ทั้ง Planner, Todo list, Trello Board, Post it ฯลฯ ซึ่งผมก็น่าจะเรียกว่าลองมาเยอะพอสมควร จนผมมาเจอ Bujo หรือ Bullet Journaling เมื่อ 2 ปีที่แล้วครับ\nความเดิมตอนที่แล้ว แนะนำ BuJo เมื่อชีวิตอยากติด Analog บล็อกเต็มๆ ที่ผมเขียนเมื่อสองปีที่แล้วที่คนเข้ามาอ่านตอนนี้เกิน 40k คลิกไปแล้ว โพสนี้จะเรียกได้ว่าเป็นภาคต่อของบทความนั้นก็ได้\nเรื่องราวหลังจากผมใช้ Bujo ได้ไม่กี่เดือนตอนนั้นคือ ผมถอย iPad ครับ และนั่นน่าจะเป็นจุดเริ่มต้นที่ผมกลับมาหาโลก Digital อีกรอบนึง ถึงแม้ว่าจะพยายามทำ Bujo บน GoodNotes เท่าไร แต่ก็ยอมรับว่าสัมผัสการเขียนใน iPad ยังไงมันก็ยังสู้กระดาษและปากกาไม่ได้ แต่ผมว่าเหตุผลที่สำคัญที่สุดที่ทำให้ผมหยุดทำ Bujo ไปในรอบนั้นคือความ Digital Native ของมันครับ\nนิยาม Digital native ของผมคือการพิมพ์ การถ่ายรูป Capture screenshot ฯลฯ ซึ่งนั่นทำให้เราขาดคีย์สำคัญของ Bujo ไปข้อนึงซึ่งผมไม่ได้คิดถึงตอนนั้น คือความสามารถในการประมวลผลข้อความแล้วสรุปครับ หรือทาง Bujo น่าจะเรียกว่า Rapid logging ทำให้ตอนนั้นวิธีการจดของผมเปลี่ยนไปมากคือ ด้วยความที่เป็นคนพิมพ์สัมผัสได้อยู่แล้ว เลยจดมันทุกอย่าง แล้วหลายๆ อย่างจนไม่ได้เอากลับมาคิดว่าจดไปทำไมนะ ซึ่งสุดท้ายผมก็เลิกทำ Bujo ไปแล้วแทนที่ด้วยอะไรก็ไม่รู้ ไม่มีชื่อเรียก แล้วแต่ tools จะพาไป\nกลับมา สาเหตุที่กลับมาทำ Analog Bujo ในรอบนี้ของผมหลักๆ เกิดจาก 2 เหตุผลครับ คือ มีเพื่อนมาชวนไปสอนทำ Bullet journaling ครับ ซึ่งหลังจากเตรียมตัวที่จะสอนได้แปปนึง ผมก็ค้นพบว่าผมสอนไม่ได้ และทำให้ผมค้นพบว่าผมใช้ชีวิต Automatic เกินไปจากแต่ก่อนมาก แล้ว Reflect กับทุกๆ อย่างที่พุ่งเข้ามาหาตัวเราจนเราเสีย self esteem ไปหลายๆ ครั้งเหมือนกัน\nตอนช่วงเตรียมตัวสอนมันทำให้ผมกลับมาอ่าน Bullet Journaling ที่ Ryder Carroll ซึ่งเราน่าจะเรียกได้ว่าเป็นบิดาแห่ง Bujo เขียนอีกครั้ง แล้วผมค้นพบคุณค่าหลายๆ อย่างที่ผมไม่เคยพบตอนทำ Bujo เมื่อสองปีก่อนในนั้นครับ\nยกตัวอย่างเช่น ผมเคยประสบปัญหากับการต้องกลับมาจดเรื่องต่อๆ กันแล้วหาไม่เจอ ถึงแม้จะทำ Indexing ไว้แล้วก็ตาม แต่พอรู้จักกับ Concept ของ Thread มันทำให้เรื่องราวแนวๆ เดียวกันสามารถเรียงร้อยต่อกันได้ง่ายมาก เพียงแค่เพิ่มเลขหน้าของเรื่องแนวเดียวกันถัดไปไว้ข้างๆ เลขหน้าในเรื่องปัจจุบันครับ\nรูปจาก bulletjournal.com/blogs/bulletjournalist/th..\nอีกสิ่งหนึ่งที่ผมค้นพบว่าทำไมผมถึงเลิกทำไปในรอบก่อนคือ เรื่องง่ายๆ อย่างสีครับ คือ Bujo เนี่ย ถ้าเราไป Search ตาม Youtube, Pinterest หลายๆ ครั้งเราจะค้นพบว่าแต่ละคนทำโคตรสวยเลย ใช้สี ทำ Caligraphy แต่งสติ๊กเกอร์​ ฯลฯ ซึ่ง รอบแรกผมก็พยายามทำแบบนั้นนะ แบบมีปากกาเมจิกติดตัวหลายสีมาก แล้วก็ค้นพบว่าตัวเองใช้หลักๆ อยู่ 3 สี แล้วมันก็ไม่สวยเลย แล้วมันก็รู้สึกเฟลเบาๆ ว่าทำไม ทำไม่ได้ขนาดนั้นนะ\nซึ่งกลับมารอบนี้ ด้วยความที่รู้ตัวละว่า มันไม่ไหวละนะ ผมเลยจับพลัดจับพลูไปเจอปากกา Fineliner ซึ่ง แค่เป็นสมุดจุด กับปากกา Fineliner แค่นี้ก็ผมก็พอใจแล้ว แล้วไม่ต้องใช้ effort เยอะเท่าสีด้วย (เพราะมีแค่สีเดียว) และหัว 0.3 เนี่ยเป็นอะไรที่กำลังดีมากๆ แล้วพอมันมีแค่เส้น มันทำให้เราลดพลังที่ใช้ในการ setup น้อยลงไปมาก เพราะไม่ต้องคิดอะไร แล้วมันก็จะคล้ายๆ กันในแต่ละเดือน ซึ่งผ่านมา 4 สัปดาห์ หลายๆ อย่างค่อยๆ วิวัฒนาการ ตัดบ้าง เพิ่มบ้าง จนมันถึงจุดที่เราโอเค\nสิ่งสำคัญ ปีที่ผ่านมา ผมเชื่อว่าตัวเองอ่านหนังสือน้อยมาตลอด คือรู้สึกว่าไม่ได้อ่านเลย เอาเวลาไปไถ Facebook, Twitter หรือไม่ก็นั่งแช่ Youtube หมด ซึ่งเอาจริงๆ มันเฟลมากนะ เพราะว่าก็ซื้อหนังสือแทบจะตลอดอยู่แล้ว และมีหนังสือที่ดองไว้เยอะมาก\nหนึ่งในเครื่องมือที่กลับมาพร้อมกับ Bujo คือ Tracker ครับ ซึ่งเอากลับมาแก้ปัญหาชีวิต Automatic ที่ผมเกริ่นไว้ก่อนหน้านี้ได้ค่อนข้างจะอยู่หมัดเลย คือมันทำให้เรามีสติมากขึ้นในหลายๆ ครั้ง และเห็นอะไรชัดขึ้นมากกว่าแต่ก่อน และมันเปลี่ยนความเชื่อผมข้างบนไปเลยเพราะ\nผมอ่านหนังสือเยอะกว่าที่คิดไว้มาก\nซึ่งพอมามองย้อนดู มันภูมิใจในตัวเองมากเลยนะ ที่เห้ย เราก็ไม่ได้เป็นคนที่แย่แบบที่เราคิดนิ เรายังเป็นคนเดิมที่เคยเป็นนี่แหละ เพียงแต่ตอนที่เราไม่ได้กลับมาหยุดคิด ตั้งสติ และ Track มัน เราก็หลงลืมความเป็นตัวเองไปเยอะมาก และมองตัวเองตามแบบที่คนอื่นมอง\nตอนผมอ่านหนังสือ Bullet Journaling คุณ Ryder Carroll เค้าบอกไว้ว่า ให้ลองทำ Migration ซักครั้งแล้วจะรู้ว่าตัวเองเหมาะกับ Bujo รึเปล่า ต้องบอกว่า ตอนทำรอบที่แล้วผมไม่ได้คิดอะไรลึกซึ้งขนาดนั้นนะ ก็แค่ย้าย Task ค้างๆ ไปที่ใหม่ ผมเข้าใจแค่นั้น\nรอบนี้ผมค้นพบว่า จังหวะที่กลับมาดู Task แต่ละ Bullet ที่ผมจดไว้ ค้างไว้บ้าง เสร็จบ้าง มันทำให้ผมเห็นว่า ผมมีความฝันหลายอย่างนะ ความฝันที่บางครั้ง เราก็ลืมไปในเวลาที่เหนื่อยล้า เห็นไอเดียที่เริ่มก่อรูปร่าง แต่ต้องหยุดทำไปเพราะต้องไปทำอย่างอื่น\nสิ่งเหล่านี้พอเรากลับมามองมัน มันไม่ได้หายไปไหนครับ และพอถึงจุดนี้เราเลือกได้ว่า เราจะพามันไปต่อ หรือเราอาจจะวางมันไว้ในอดีต รอวันที่จะกลับมาพบอีกครั้ง หรือเราอาจจะเลือกที่จะปล่อยมันไป แต่สิ่งสำคัญตอน Migration คือ \u0026ldquo;เรามีโอกาสที่จะเลือกมัน\u0026rdquo; และนี่แหละครับ มันทำให้ผมรู้สึกว่าชีวิตผมมันกลับมา Control ได้มากขึ้นกว่าเดิม ไม่ได้เป็นมนุษย์​ Automatic อีกแล้ว\nสุดท้ายเอาจริงๆ ผมก็ไม่รู้หรอกว่ารอบนี้จะทำต่อไปได้อีกกี่เดือน แต่ตอนนี้กลับมาทำแล้วชีวิตดีก็คงจะทำต่อไปแหละ ต้องขอบคุณเพื่อนวิวที่ชวนไปสอน ถึงแม้จะไม่ได้ไปช่วยสอนจริงๆ ไม่งั้นคงไม่ได้กลับมามองเครื่องมือนี้อีกครั้ง ขอบคุณธันวาที่มาชวนคุยเรื่อง Bujo ในช่วงเวลาใกล้ๆ กัน มันคงเป็นเรื่องบังเอิญมากที่สองคนนี้มาทักเรื่อง Bujo ในเวลาใกล้ๆ กัน แต่เรื่องบัญเอิญจะไม่หายไปตามกาลเวลา ถ้าเรายังจำมันได้อยู่และสิ่งที่ทำให้เราจำมันได้ก็คือตัว Bujo นี่แหละ สวัสดี\n","permalink":"https://yothinix-com.pages.dev/bujo-part2/","summary":"\u003cp\u003eในโลกที่วุ่นวาย และงานที่ถาโถม ทำให้ตลอดชีวิตที่ผ่านมา ไม่ทางใดก็ทางหนึ่ง ผมมักจะหาทางจัดการตัวเองผ่านอะไรซักอย่าง ซึ่งอาจจะเป็นได้ทั้ง Planner, Todo list, Trello Board, Post it ฯลฯ ซึ่งผมก็น่าจะเรียกว่าลองมาเยอะพอสมควร จนผมมาเจอ Bujo หรือ Bullet Journaling เมื่อ 2 ปีที่แล้วครับ\u003c/p\u003e\n\u003ch2 id=\"ความเดมตอนทแลว\"\u003e\u003cstrong\u003eความเดิมตอนที่แล้ว\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"/bujo-part2/M5rbHF6xz_hu_720eebaab3b87f2a.webp\"\n       srcset=\"/bujo-part2/M5rbHF6xz_hu_f559af8e922a9430.webp 480w, /bujo-part2/M5rbHF6xz_hu_f65b74e710591390.webp 960w, /bujo-part2/M5rbHF6xz_hu_720eebaab3b87f2a.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"711\"\n       alt=\"Screen Shot 2563-11-02 at 20.49.42.png\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"/bujo/\"\u003eแนะนำ BuJo เมื่อชีวิตอยากติด Analog\u003c/a\u003e บล็อกเต็มๆ ที่ผมเขียนเมื่อสองปีที่แล้วที่คนเข้ามาอ่านตอนนี้เกิน 40k คลิกไปแล้ว โพสนี้จะเรียกได้ว่าเป็นภาคต่อของบทความนั้นก็ได้\u003c/p\u003e\n\u003cp\u003eเรื่องราวหลังจากผมใช้ Bujo ได้ไม่กี่เดือนตอนนั้นคือ ผมถอย iPad ครับ และนั่นน่าจะเป็นจุดเริ่มต้นที่ผมกลับมาหาโลก Digital อีกรอบนึง ถึงแม้ว่าจะพยายามทำ Bujo บน GoodNotes เท่าไร แต่ก็ยอมรับว่าสัมผัสการเขียนใน iPad ยังไงมันก็ยังสู้กระดาษและปากกาไม่ได้ แต่ผมว่าเหตุผลที่สำคัญที่สุดที่ทำให้ผมหยุดทำ Bujo ไปในรอบนั้นคือความ Digital Native ของมันครับ\u003c/p\u003e\n\u003cp\u003eนิยาม Digital native ของผมคือการพิมพ์ การถ่ายรูป Capture screenshot ฯลฯ ซึ่งนั่นทำให้เราขาดคีย์สำคัญของ Bujo ไปข้อนึงซึ่งผมไม่ได้คิดถึงตอนนั้น คือความสามารถในการประมวลผลข้อความแล้วสรุปครับ หรือทาง Bujo น่าจะเรียกว่า Rapid logging ทำให้ตอนนั้นวิธีการจดของผมเปลี่ยนไปมากคือ ด้วยความที่เป็นคนพิมพ์สัมผัสได้อยู่แล้ว เลยจดมันทุกอย่าง แล้วหลายๆ อย่างจนไม่ได้เอากลับมาคิดว่าจดไปทำไมนะ ซึ่งสุดท้ายผมก็เลิกทำ Bujo ไปแล้วแทนที่ด้วยอะไรก็ไม่รู้ ไม่มีชื่อเรียก แล้วแต่ tools จะพาไป\u003c/p\u003e","title":"เรากลับมาทำ BuJo ได้หนึ่งเดือนแล้ว"},{"content":"Installation ลง Liquibase ใน pom.xml \u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.liquibase\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;liquibase-core\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.6.2\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; เพิ่ม configuration ให้ liquibase ใน application.properties\n## Liquibase spring.liquibase.enabled=true spring.liquibase.parameters.EnumDataType=ENUM(\u0026#39;VALUE1\u0026#39;, \u0026#39;VALUE2\u0026#39;, \u0026#39;VALUE3\u0026#39;) spring.liquibase.contexts=local ตัวสำคัญคือ spring.liquibase.contexts ตัวนี้เหมือนคอยบอกว่าเรารัน Spring โหมดอะไรอยู่ แล้วทำให้เราใช้ connection database ที่เราเซตไว้ใน spring ได้ด้วย\nอีกจุดนึงคือ spring.liquibase.parameters อันนี้เป็น custom parameter ที่เราเอาไว้ใช้ใน Changeset ซึ่งบางครั้งของ database คนละแบบจะต่างกันอย่างเช่น type ENUM ของ H2 เก็บเป็น enum ได้เลย แต่ PostgreSQL ตัว spring จะแปลงเป็น INT เลยต้องมาประกาศไว้ด้วย\nUsage เพิ่มไฟล์ ChangeLog master ไฟล์นี้เป็นเหมือนไฟล์หลักไว้บอกว่ามี migration step อะไรบ้างผ่าน property ชื่อ include.file ไฟล์กับชื่อจะอยู่ที่ /resources/db/changelog/db.changelog-master.yaml ตัวนี้สามารถตั้งค่าให้ไปอยู่ที่อื่น ชื่ออื่นได้ แต่อันนี้คือชื่อ default หน้าตาของไฟล์จะประมาณ databaseChangeLog: - include: file: db/changelog/001-add-user-table.yaml สร้าง ChangeSet ตัวนี้ไว้บอกว่าใน migration นี้มี change อะไรเกี่ยวกับ database บ้าง ตัวอย่างเช่นของ user databaseChangeLog: - changeSet: id: 001-add-user-table author: man changes: - createTable: columns: - column: constraints: nullable: false primaryKey: true primaryKeyName: user_pkey name: id type: UUID - column: constraints: nullable: false name: name type: VARCHAR(250) - column: constraints: nullable: false name: type type: ${EnumDataType} - column: name: is_admin type: BOOLEAN - column: name: created_at type: TIMESTAMP tableName: user ใน changeSet ต้องบอกว่ามันเป็น changeSet ซึ่งมี property หลักๆ ที่ใช้คือ\nid: อันนี้เอาไว้เป็น identifier ไม่ unique ก็ได้ลองแล้วติด แต่ best practice คือจะรันเลขหรือรันเป็นชื่อก็ได้ นี่เลยเอาทั้งสองอย่างแล้วเอาให้เป็นชื่อเดียวกับไฟล์ของ changeset เลยจะได้หาง่ายๆ author: ก็คือใครสร้าง changeset นี้ changes: อันนี้เป็นตัวบอกว่าเราจะทำอะไรเกี่ยวกับ database ในตัวอย่างข้างล่างคือ createTable โน๊ตนิดหน่อยเกี่ยวกับ createTable คือมันต้องการ key หลักสองอย่างคือ columns, tableName ก็ตามตัวเลย แต่ใน columns จะมีรายละเอียดนิดหน่อย\n- column: constraints: nullable: false primaryKey: true primaryKeyName: user_pkey name: id type: UUID ใน column required หลักๆ คือ name กับ type ซึ่งตามที่ใช้ใน SQL ที่สร้างของ database ตัวนั้นเลย ส่วน constraints เป็น optional\nในตัวอย่างจะเห็น type: ${EnumDataType} อันนี้จะเอามาจากที่เราประกาศไว้ใน spring.liquibase.parameters ใน application.properties มาใส่ให้\n- addUniqueConstraint: constraintName: uq_admin_name_user columnNames: name, is_admin tableName: user อีกตัวอย่างเป็นการสร้าง unique constraints ของ table อันนี้ใช้คำสั่ง addUniqueConstraint ในเลเวลเดียวกับ createTable เลย ตรงนี้ required แค่ tableName กับ columnNames ส่วนชื่อถ้าไม่ใส่มันจะเรียงๆ ให้จาก properties ที่เราใส่ไป แนะนำให้ใส่ดีกว่า\nHow it work เวลาที่ Spring ทำงาน มันจะสั่งรัน liquibase update ให้อัตโนมัติซึ่ง ถ้ายังไม่เคยมี liquibase ทำครั้งแรกมันจะสร้าง table ไว้เก็บ migration step หรือ changelog ด้วยหน้าตาแบบนี้\nexampledb\u0026gt; select * from databasechangelog; +-------------------------------------+----------+-------------------------------------------------------+----------------------------+-----------------+------------+------------------------------------+------------------------------------------------------------------- | id | author | filename | dateexecuted | orderexecuted | exectype | md5sum | description |-------------------------------------+----------+-------------------------------------------------------+----------------------------+-----------------+------------+------------------------------------+------------------------------------------------------------------- | 001-add-user-table | man | db/changelog/001-add-user-table.yaml | 2020-10-27 10:12:27.875734 | 1 | EXECUTED | 8:09d73c59f70e73a65420a4eb3f044bc8 | createTable tableName=user +-------------------------------------+----------+-------------------------------------------------------+----------------------------+-----------------+------------+------------------------------------+------------------------------------------------------------------- สำคัญอย่างนึงคือตัว changeset ถ้าถูก execute ไปแล้วห้ามกลับไปแก้เด็ดขาด เพาะ md5sum มันจะไม่ตรงกัน แล้วมันจะไม่ยอม migrate ให้ ถึงแม้ว่า liquibase-maven-plugin จะสั่ง clear checksum ได้ แต่ดีที่สุดคืออย่าไปยุ่งกับมันเลย\nUnit test setup ถ้าเรา setup เท่าข้างบนแล้วไปรัน unit test เลย สิ่งที่เกิดขึ้นคือ\njava.lang.IllegalStateException: Failed to load ApplicationContext ... Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name \u0026#39;liquibase\u0026#39; defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ArrayIndexOutOfBoundsException: 1 ซึ่งหาเท่าไรใน Stackoverflow ก็หาไม่เจอ (ลองแล้วทุก link) แต่วิธีแก้คือให้ไปเพิ่ม liquibase property ใน application.properties ของเทสก็จะได้ละ\nspring.liquibase.enabled=true spring.liquibase.parameters.EnumDataType=ENUM(\u0026#39;VALUE1\u0026#39;, \u0026#39;VALUE2\u0026#39;, \u0026#39;VALUE3\u0026#39;) Further reading จริงๆ อยากให้มันสร้าง changeLog จาก Entity ได้เลยแต่ยังหาวิธีไม่ได้ แล้วก็ liquibase-maven-plugin ใช้กับ intelliJ ก็ยังเอ๋อๆ อยู่\nอีกอย่างคือ ในตัวอย่างที่ยกมามีแต่ forward migration ยังไม่มี rollback ซึ่งจริงๆ มัน support rollback นะ แล้วก็เขียนอยู่ใน changeSet นะแหละ แต่ยังไม่ได้ดูเพิ่ม\nNote Liquibase Maven plugin เอาไว้สั่ง liquibase แบบไม่ต้อง start Spring แต่ต้องลง dependencies ของมันเองด้วย\n\u0026lt;dependencies\u0026gt; \u0026lt;dependency\u0026gt; \u0026lt;groupId\u0026gt;org.liquibase\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;liquibase-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.6.2\u0026lt;/version\u0026gt; \u0026lt;/dependency\u0026gt; \u0026lt;/dependencies\u0026gt; ... \u0026lt;build\u0026gt; \u0026lt;plugins\u0026gt; \u0026lt;plugin\u0026gt; \u0026lt;groupId\u0026gt;org.liquibase\u0026lt;/groupId\u0026gt; \u0026lt;artifactId\u0026gt;liquibase-maven-plugin\u0026lt;/artifactId\u0026gt; \u0026lt;version\u0026gt;3.6.2\u0026lt;/version\u0026gt; \u0026lt;configuration\u0026gt; \u0026lt;propertyFile\u0026gt;src/main/resources/liquibase.properties\u0026lt;/propertyFile\u0026gt; \u0026lt;/configuration\u0026gt; \u0026lt;/plugin\u0026gt; \u0026lt;/plugins\u0026gt; \u0026lt;/build\u0026gt; liquibase.properties อันนี้เอาไว้ให้ liquibase-maven-plugin คุยกับ database ได้โดยไม่ต้องง้อ Spring เพราะปกติ Spring จะเป็นคนรัน Liquibase ให้อยู่แล้ว\nchangeLogFile=src/main/resources/db/changelog/db.changelog-master.yaml url=jdbc:postgresql://localhost:5432/exampledb driver=org.postgresql.Driver username=user password=password Reference ถ้า setup ง่ายๆ ดูตามนี้ได้ แต่ไฟล์ changelog, changeset เค้าใช้เป็น XML ซึ่งอ่านยากกว่า YAML https://www.baeldung.com/liquibase-refactor-schema-of-java-app วิธีเพิ่ม unique constraint ให้ table https://docs.liquibase.com/change-types/community/add-unique-constraint.html อันนี้ช่วยหาคำตอบตอน Spring context, profile หาไม่เจอกับ liquibase https://stackoverflow.com/questions/40088915/using-spring-boot-profiles-with-liquibase-changeset-context-attribute-to-manage อันนี้ช่วยหาคำตอบตอนหาไฟล์ master changelog ไม่เจอ https://stackoverflow.com/questions/41990295/java-illegalstateexception-cannot-find-changelog-location-class-path-resourc ตัวอย่างนี้ดีเพราะใช้ YAML แล้วก็รู้เรื่อง liquibase.parameters จากที่นี่แหละ https://reflectoring.io/database-migration-spring-boot-liquibase/ อันนี้ช่วยหาคำตอบให้ตอนงงๆ liquibase.properties ว่าตกลงใช้ไม่ใช้ https://watson.earth/2018/09/21/combining-spring-boot-and-liquibase/ อันนี้ดูค้างไว้เรื่อง Rollback, pre-condition ของ changeset ว่าใช้ยังไง https://docs.liquibase.com/concepts/advanced/preconditions.html อันนี้ดีมาก เป็น Best Practice ของ Liquibase เองเลย หลายๆ อย่างได้มาจากอันนี้แหละ https://www.liquibase.org/get-started/best-practices อันนี้พูดถึง liquibase-maven-plugin โดยเฉพาะ https://docs.liquibase.com/tools-integrations/maven/home.html ","permalink":"https://yothinix-com.pages.dev/liquibase-spring-boot-setup/","summary":"\u003ch2 id=\"installation\"\u003e\u003cstrong\u003eInstallation\u003c/strong\u003e\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eลง Liquibase ใน pom.xml\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;dependencies\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u0026lt;dependency\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u0026lt;groupId\u0026gt;org.liquibase\u0026lt;/groupId\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u0026lt;artifactId\u0026gt;liquibase-core\u0026lt;/artifactId\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u0026lt;version\u0026gt;3.6.2\u0026lt;/version\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u0026lt;/dependency\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026lt;/dependencies\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eเพิ่ม configuration ให้ liquibase ใน \u003ccode\u003eapplication.properties\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ## Liquibase\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e spring.liquibase.enabled=true\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e spring.liquibase.parameters.EnumDataType=ENUM(\u0026#39;VALUE1\u0026#39;, \u0026#39;VALUE2\u0026#39;, \u0026#39;VALUE3\u0026#39;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e spring.liquibase.contexts=local\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eตัวสำคัญคือ \u003ccode\u003espring.liquibase.contexts\u003c/code\u003e ตัวนี้เหมือนคอยบอกว่าเรารัน Spring โหมดอะไรอยู่ แล้วทำให้เราใช้ connection database ที่เราเซตไว้ใน spring ได้ด้วย\u003c/p\u003e\n\u003cp\u003eอีกจุดนึงคือ \u003ccode\u003espring.liquibase.parameters\u003c/code\u003e อันนี้เป็น custom parameter ที่เราเอาไว้ใช้ใน Changeset ซึ่งบางครั้งของ database คนละแบบจะต่างกันอย่างเช่น type ENUM ของ H2 เก็บเป็น enum ได้เลย แต่ PostgreSQL ตัว spring จะแปลงเป็น INT เลยต้องมาประกาศไว้ด้วย\u003c/p\u003e\n\u003ch2 id=\"usage\"\u003e\u003cstrong\u003eUsage\u003c/strong\u003e\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eเพิ่มไฟล์ ChangeLog master ไฟล์นี้เป็นเหมือนไฟล์หลักไว้บอกว่ามี migration step อะไรบ้างผ่าน property ชื่อ \u003ccode\u003einclude.file\u003c/code\u003e ไฟล์กับชื่อจะอยู่ที่ \u003ccode\u003e/resources/db/changelog/db.changelog-master.yaml\u003c/code\u003e ตัวนี้สามารถตั้งค่าให้ไปอยู่ที่อื่น ชื่ออื่นได้ แต่อันนี้คือชื่อ default หน้าตาของไฟล์จะประมาณ\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    databaseChangeLog:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      - include:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          file: db/changelog/001-add-user-table.yaml\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003eสร้าง ChangeSet ตัวนี้ไว้บอกว่าใน migration นี้มี change อะไรเกี่ยวกับ database บ้าง ตัวอย่างเช่นของ user\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-gdscript3\" data-lang=\"gdscript3\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003edatabaseChangeLog\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003echangeSet\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e001\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003euser\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003eauthor\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eman\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"n\"\u003echanges\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecreateTable\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003ecolumns\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecolumn\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003econstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"n\"\u003enullable\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"bp\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"n\"\u003eprimaryKey\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"bp\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"n\"\u003eprimaryKeyName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003euser_pkey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eid\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eUUID\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecolumn\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003econstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"n\"\u003enullable\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"bp\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eVARCHAR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e250\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecolumn\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003econstraints\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"n\"\u003enullable\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"bp\"\u003efalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etype\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"o\"\u003e$\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eEnumDataType\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecolumn\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eis_admin\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eBOOLEAN\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecolumn\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ecreated_at\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eTIMESTAMP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003etableName\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003euser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eใน changeSet ต้องบอกว่ามันเป็น changeSet ซึ่งมี property หลักๆ ที่ใช้คือ\u003c/p\u003e","title":"บันทึกวิธีใช้ liquibase ทำ database migration ให้ Spring boot"},{"content":"ช่วงนี้ผมต้องมาขึ้น Django project ใหม่กับทีมครับ ซึ่งพอขึ้น Project ใหม่ หนึ่งใน Development workflow ที่มาคู่กันคือ การต้องเอา Database จาก Production กลับมาใช้ที่ Local development ให้ได้ เพื่อที่จะ debug ปัญหาหลายๆ อย่างได้กับ Data บน Production หรือ เพื่อความสะดวกสบายในการ Development ครับ\nทีนี้ที่ผ่านมามันไม่ค่อยมีปัญหาเพราะ Database ผมมักจะใช้ PostgreSQL ซึ่งอาจจะอยู่ใน database Instance ของตัวเอง อยู่บน Container ของตัวเอง ฯลฯ ซึ่งก็ใช้ pg_dump กับ pg_restore คู่กันง่ายๆ มาตลอด ไม่มีปัญหายเว้นอัพเกรด PostgreSQL major version ที่ไฟล์ format เปลี่ยนนิดหน่อยก็ตามอัพเกรด client กัน\nปัญหามันอยู่ที่ Media files ครับ ซึ่งถ้าเลือกได้ ผมจะเลือกใช้ django-storages เพื่อที่จะ offload ตัว media file ไปเก็บไว้ใน object storage เช่น Amazon s3 หรือ Google Cloud Storage ครับ แต่ใน use case ที่เราเลือกไม่ได้ต้องเก็บไฟล์ลง server เท่านั้น เราจะทำยังไงหละ\nพอมี Use case แบบนี้แวบแรกที่ผมคิดออกคือ rsync เลยครับ ง่ายๆ บ้านๆ sync directory ที่ต้องเก็บ Media กลับมาลงใน local แต่ผมตั้งคำถามกับตัวเองว่ามันมีวิธีอื่นมั้ย มันเลยเกิด post นี้ขึ้นนี่แหละครับ\nDjango Database Backup ผมค้นไปเจอ django-dbbackup เพราะคิดว่าจะทำยังไงถึงจะ backup database / media files ได้พร้อมกันเลย ไม่ต้องมานั่งทำทีละอย่าง เรียกได้ว่า รันคำสั่งเดียวปุ๊ปได้ Data พร้อมใช้งานใน local เลย ซึ่งสารภาพว่าแวบแรกก็นึกว่าจะเขียน Ansible playbook ไปเลย แต่ถ้าทีมไม่ได้มี Technical ลึกหละ\nตัว Django Database Backup นี่เป็น Package ที่ไม่ได้ซับซ้อนอะไรเลยครับ ไม่ได้ Reinvent the wheel การ backup ขึ้นมาใหม่ เป็นไอเดียง่ายๆ แค่ dump / restore ไฟล์ อาจจะรวม compresion กับ encryption ขึ้นมานิดหน่อย แต่ไม่ได้สลับซับซ้อนอะไรเลย โดยตัว Package จะเป็น extension app ของ Django ที่ provide management command ต่างๆ มาให้เราทำงานได้ง่ายขึ้นครับ\nวิธีลงไม่ยากแค่สั่ง pip install django-dbbackup หรือจะเพิ่ม dependencies ลงใน requirements.txt, Pipfile, pyproject.toml เอาที่สะดวกเลยครับ พอลงเสร็จแล้วมีจุดที่เราต้อง config เบื้องต้นเพิ่มใน Django settings file เรา 2 อย่าง\nอย่างแรกเลยคือให้เราเพิ่ม INSTALLED_APPS ชื่อ dbbackup ลงไปครับ ซึ่งจะเอาไว้ตรงไหนก็ได้ order ไม่สำคัญ\nINSTALLED_APPS = ( ... \u0026#39;dbbackup\u0026#39;, # django-dbbackup ) อย่างที่สองคือ เราต้องเพิ่ม settings เพื่อที่จะบอกว่า Backup เราเนี่ยจะเก็บไว้ที่ไหน​ซึ่งสามารถเก็บไว้ได้ทั้ง Amazon S3, Dropbox, FTP แต่ในเคสง่ายๆ เราเก็บไว้ใน File System ในโปรเจ็คเราก็ได้ครับหน้าตาประมาณนี้\nDBBACKUP_STORAGE = \u0026#39;django.core.files.storage.FileSystemStorage\u0026#39; DBBACKUP_STORAGE_OPTIONS = {\u0026#39;location\u0026#39;: \u0026#39;/app/backups\u0026#39;} ตรงจุดนี้ระวังนิดนึงนะครับมี bug ใน document ตรง DBBACKUP_STORAGE มันจะชี้ไปที่ dbbackup.storage.filesystem_storage ซึ่งที่ถูกต้องคือ django.core.files.storage.FileSystemStorage ครับ\nUsage หลังจากที่เราติดตั้งเสร็จแล้ว config เสร็จแล้วทีนี้เราก็สามารถใช้งาน Django database backup ได้แล้วครับ ซึ่งมันไม่ได้แค่ backup database ตามชื่อ แต่ครอบคลุมไปถึง Media ด้วย\nBackup / restore Media ถ้าเราจะ Backup ตัว Media file เราก็ใช้ management command mediabackup ได้เลยครับตัว output จะออกมาคล้ายๆ ตัวอย่างข้างล่างเลย คือเป็นไฟล์ compress ของ media ใน Django app เราครับ\n$ python manage.py mediabackup Writing file to 7b23e710c576-2020-05-17-044731.tar ส่วนถ้าเราอยากจะ restore ก็แค่ใช้ command mediarestore ครับ ซึ่งสามารถเลือกไฟล์เองก็ได้ แต่ถ้า structure ของไฟล์ไม่ต่างกันเราสามารถเรียกได้เลยครับ แล้วตัว Django dbbackup มันฉลาดพอจะเลือกไฟล์ล่าสุดมา restore ครับ รวมถึงถ้าไม่มี directory ก็จะสร้างให้หมดเลยด้วย\n$ python manage.py mediarestore Restoring backup for media files Finding latest backup Restoring: 7b23e710c576-2020-05-17-044843.tar Are you sure you want to continue? [Y/n] Y some_media_path/image1.png uploaded some_media_path/image2.png uploaded some_media_path/image3.png uploaded Backup / Restore Database ในส่วนของ Backup database จะมีความยุ่งยากกว่า Media นิดนึงตรงที่เราต้องมี client ของ Database ตัวนั้นจริงๆ อยู่ในเครื่องที่เราจะรัน command นี้ด้วยครับเช่น เคสผมใช้ PostgreSQL ก็ต้องมี postgresql-client ในเครื่องก่อน มันถึงจะพาเพื่อนอย่าง pg_dump, pg_restore มาด้วย แต่ข้อควรระวังอีกอย่างคือ ลง postgrsql-client ให้มันตรงกับ version PosgreSQL ที่เราใช้ด้วยนะครับ ในเคสนี้ผมแค่สั่ง apt install postgresql-client-12 ก็เรียบร้อยครับ\nพอเรามี client ในเครื่องแล้วที่เหลือก็ง่ายเลย แทนที่เราจะต้องมาสั่ง pg_dump ด้วย option ยาวๆ เราก็ใช้ management command dbbackup สั่ง โดยตัว Django dbbackup ก็จะไปดูด database settings\nของเรามา fill ให้ไม่ต้องมาจำเอง\n$ python [manage.py](http://manage.py/) dbbackup Backing Up Database: postgres Writing file to default-7b23e710c576-2020-05-17-050714.psql ส่วนวิธี restore ก็จะเก่งเหมือน Media restore ที่รู้จักไฟล์ล่าสุดครับ ส่วน command ก็สั้นๆ แค่ dbrestore พอสั่งเสร็จเราก็ได้ database backup มาใช้ละ\n$ python manage.py dbrestore Finding latest backup Restoring backup for database \u0026#39;default\u0026#39; and server \u0026#39;None\u0026#39; Restoring: default-7b23e710c576-2020-05-17-050714.psql Restore tempfile created: 62.2 KiB Are you sure you want to continue? [Y/n] Y จบแล้วครับ ง่ายๆ แค่นี้เลย จริงๆ ตัว Django dbbackup ยังทำอย่างอื่นได้อีกทั้ง encryption , filename prefix หรือ จะตั้ง limit ให้เก็บแค่กี่ไฟล์ล่าสุดก็ได้ ก็ลองอ่านได้ใน Documentation ครับเขียนไว้ค่อนข้างอ่านง่ายเลย ก็หวังว่าชีวิตจะง่ายขึ้นกันนะครับ หลังจากนี้ 🐍🐮\nReference https://github.com/django-dbbackup/django-dbbackup https://django-dbbackup.readthedocs.io/en/stable/ ","permalink":"https://yothinix-com.pages.dev/django-dbbackup/","summary":"\u003cp\u003eช่วงนี้ผมต้องมาขึ้น Django project ใหม่กับทีมครับ ซึ่งพอขึ้น Project ใหม่ หนึ่งใน Development workflow ที่มาคู่กันคือ การต้องเอา Database จาก Production กลับมาใช้ที่ Local development ให้ได้ เพื่อที่จะ debug ปัญหาหลายๆ อย่างได้กับ Data บน Production หรือ เพื่อความสะดวกสบายในการ Development ครับ\u003c/p\u003e\n\u003cp\u003eทีนี้ที่ผ่านมามันไม่ค่อยมีปัญหาเพราะ Database ผมมักจะใช้ PostgreSQL ซึ่งอาจจะอยู่ใน database Instance ของตัวเอง อยู่บน Container ของตัวเอง ฯลฯ ซึ่งก็ใช้ \u003ccode\u003epg_dump\u003c/code\u003e กับ \u003ccode\u003epg_restore\u003c/code\u003e คู่กันง่ายๆ มาตลอด ไม่มีปัญหายเว้นอัพเกรด PostgreSQL major version ที่ไฟล์ format เปลี่ยนนิดหน่อยก็ตามอัพเกรด client กัน\u003c/p\u003e\n\u003cp\u003eปัญหามันอยู่ที่ Media files ครับ ซึ่งถ้าเลือกได้ ผมจะเลือกใช้ \u003ca href=\"https://github.com/jschneier/django-storages\"\u003edjango-storages\u003c/a\u003e เพื่อที่จะ offload ตัว media file ไปเก็บไว้ใน object storage เช่น Amazon s3 หรือ Google Cloud Storage ครับ แต่ใน use case ที่เราเลือกไม่ได้ต้องเก็บไฟล์ลง server เท่านั้น เราจะทำยังไงหละ\u003c/p\u003e","title":"Backup Django ง่ายกว่านี้ไม่มีอีกแล้วด้วย django-dbbackup"},{"content":"เกริ่นก่อนว่าที่ Pronto Tools เราเปลี่ยนมาใช้ Cypress มาได้ซักพักแล้วครับแล้วเราชอบมันมาก เราเลยไม่ลังเลเลยที่จะย้ายและเพิ่ม E2E เทสมาอยู่บน Cypress ซึ่งพอเทสมันเพิ่มขึ้นอย่างรวดเร็ว เวลาที่ใช้รันมันก็เพิ่มขึ้นอย่างมีนัยยะสำคัญ\nทำไม E2E เทสถึงรันช้า 🐢 ปัญหาหลักเลยคือ E2E เทสจะค่อนข้างมี Step ที่ทำงานซ้ำๆ เกิดขึ้นบ่อยๆ เพื่อ Setup ข้อมูลให้พร้อมที่จะเทสใน TestCase หลัก ปัญหาหลักๆ ก็คืองานซ้ำๆ นั้นถ้ามันใช้เวลารันนาน ถ้ามันยิ่งมีจำนวนมากขึ้นก็จะยิ่งทำให้ชุดทดสอบเราทำงานช้าขึ้นเรื่อยๆ ลองมาดูตัวอย่างของเทสกันครับ\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.signUp() cy.visit(\u0026#39;/plan\u0026#39;) cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.signUp() cy.visit(\u0026#39;/plan\u0026#39;) cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) จากโค้ดตัวอย่างข้างต้น จะเป็นการเทสว่าหน้า Pricing Plan เราเนี่ยมันมีชื่อ Plan กับราคาอยู่ ซึ่งจะเห็นว่าการจะทดสอบ TestCase นึงนี่ เราต้องเสียเวลาไปรัน command cy.signUp() ซึ่งเป็น command ที่เราสร้างให้เอาไว้สมัครสมาชิกเข้า service เรา ซึ่งเวลาสมัครใช้งานเนี่ย มันจะมีการทำงานหลายอย่างเกิดขึ้นไม่ว่าจะเป็น สร้าง subscription user, ส่งอีเมล์ยืนยันการสมัคร, ฯลฯ แต่ละอย่างนี่ใช้เวลาทั้งนั้นครับ\nเปลี่ยนวิธีคิด 🤔 จาก Test Suite ข้างบนนะครับ พอมี TestCase ใหม่เพิ่มขึ้นด้วยสัญชาติญาณ Copy-Paste ของ Developer สิ่งที่เราจะทำก็คือ Copy step ของเทสเคสเก่าออกมาแล้วแก้ในส่วนที่จะ Assertion ซึ่งก็ยิ่งเป็นการเพิ่มเวลาที่ใช้รัน cy.signUp() ให้เพิ่มขึ้นไปอีกตัว จนเขียนเทสแก้ทีนึงก็ไปกดน้ำ ชงกาแฟรอได้เลยกว่าจะรันเสร็จ\nพอเอาเรื่องนี้ไปปรึกษาเทพบอส Automate Tester ประจำทีมเราที่มีประสบการณ์การทำ Automate test มาอย่างโชคโชน เทสบอสก็ให้คำแนะนำที่โคตรเทพกลับมาว่า\nแทนที่เราจะ sign up ใหม่ทุกครั้ง ทำไมเราไม่ setup test data แล้ว login แทนหละ\nประโยคอาจจะไม่ตามนี้เป๊ะๆ แต่ไอเดียมันประมาณนี้แหละ พอได้ยินแบบนั้นหน้าตาเทสเราเปลี่ยนไปเลยครับ\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.login() cy.visit(\u0026#39;/plan\u0026#39;) cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.login() cy.visit(\u0026#39;/plan\u0026#39;) cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) เสียดายมันทำ highlight สีไม่ได้แต่จุดที่เปลี่ยนคือแทนที่เราจะทำ command cy.signUp() ซึ่งใช้เวลานานมากในการทำงานอย่างที่กล่าวไว้ข้างต้น เราก็ setup test data ในเครื่องเป้าหมายให้เรียบร้อยก่อน ในทีนี้คือ User และข้อมูลที่เราจะ assert ที่ครอบคลุมเกือบทุกเคส หลังจากนั้นเราเปลี่ยนไปใช้ command cy.login() ซึ่งเป็น command ที่ใช้เวลาในการทำงานน้อยกว่า sign up เยอะระดับนึงเลย (เพราะไม่ต้องกรอกข้อมูลอะไรนอกจาก user / pass แล้วกด login\nDon’t Repeat Yourself 👣 พอ Test Suite มันออกมาหน้าตาแบบนี้แล้ว ด้วยสัญชาติญาณ Developer ซึ่งเกลียด Duplication เข้าไส้ เราเลยจะย้ายโค้ดซ้ำๆ มาไว้ที่เดียวกัน ซึ่ง Cypress มีจุดให้เรา setup data ก่อนจะรันเทสทุกครั้งครับ ตรงนั้นครับเรียกว่า beforeEach() ซึ่งพอย้ายแล้ว Test Suite เราก็จะออกมาหน้าตาประมาณนี้\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { beforeEach(() =\u0026gt; { cy.login() cy.visit(\u0026#39;/plan\u0026#39;) }) it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) ซึ่งจะเห็นว่าแต่ละ TestCase มันก็ยังรัน cy.login() และ cy.visit() ให้ครับ แต่ตัว test suite หน้าตาเราจะสะอาดขึ้นมาเพราะโค้ดซ้ำๆ ถูกย้ายไปไว้ใน beforeEach แล้ว\nไปให้สุดแล้วหยุดที่ before 🔥 พอเราย้ายโค้ดที่ login มาไว้ใน beforeEach แล้วจะเห็นว่าถึงแม้มันจะลดโค้ดซ้ำๆ ได้ แต่มันก็ยังทำซ้ำๆ อยู่ๆ ดี หมายความว่า เราต้องเสียเวลา login ทุกครั้งที่เริ่มทุก TestCase เลยเกิดไอเดียว่า แล้วถ้ามัน login แค่ครั้งแรกครั้งเดียวละ มันต้องรันเร็วขึ้นแน่ๆ เลย\nโชคดีที่นอกจาก Cypress จะมี beforeEach ให้ใช้แล้ว ยังมี before ให้ใช้ด้วยครับ ซึ่ง before จะต่างจาก beforeEach คือมันจะรันแค่ตอนเริ่มต้นของ context ครั้งเดียวเท่านั้น พอเรามีความรู้ตรงนี้ปั๊ป โค้ดมันเลยถูกปรับให้เป็นแบบนี้ครับ\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { before(() =\u0026gt; { cy.login() }) beforeEach(() =\u0026gt; { cy.visit(\u0026#39;/plan\u0026#39;) }) it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) แต่ว่าสิ่งที่เกิดขึ้นไม่เป็นแบบที่เราคิดครับ พอเราเปลี่ยนมาถึงจุดนี้ TestCase พังกระจายเลยครับ และบอกว่ามันไม่ได้ login ซึ่งทำให้เราประหลาดใจมาก เพราะเอ๊ะมัน login แล้วนิ มันน่าจะทำงานได้นะ\nสิ่งที่เกิดขึ้นก็คือ Cypress มันฉลาดมากครับ โดยก่อนจะเริ่มแต่ละ TestCase มันจะทำการ Clear browser state ให้ซึ่ง state ที่ว่านั้นก็คือ Cookie นั้นเองครับ เพราะว่าเวลาเรา Login web service เนี่ย มันต้องทำการเก็บ state ว่ามัน Login อยู่ไว้ซักที่ครับ ในเคสของเรา webservice เรา based on Django Web Framework ครับ โดยหลังจาก login ตัว state จะถูกเก็บไว้ที่ Cookie ที่ชื่อ sessionid และอีกอันนึงคือ csrftoken ครับ\nพอเรารู้แบบนี้ สิ่งที่เราคิดต่อมาคือ เราจะทำยังไงให้ Cypress มันไม่ clear cookie ก่อนจะเริ่มรันแต่ละเทส หลังจากค้น Document มาเราก็ไปเจอ command ข้างล่างนี้ครับ\nCypress.Cookies.preserveOnce() โดย command นี้จะมีหน้าที่บอกว่าก่อนเริ่มต้น TestCase ใหม่ ไม่ต้อง reset cookie 2 ตัวที่ระบุทิ้งไว้นะโว้ย เราเลยเอามาปรับใช้กับ Test Suite ของเราออกมาหน้าตาเป็นแบบนี้ครับ\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { before(() =\u0026gt; { cy.login() }) beforeEach(() =\u0026gt; { Cypress.Cookies.preserveOnce(\u0026#39;sessionid\u0026#39;, \u0026#39;csrftoken\u0026#39;) cy.visit(\u0026#39;/plan\u0026#39;) }) it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) ทีนี้เราก็สามารถทำให้ Test Suite เรา Login ครั้งเดียวแล้วรัน TestCase ทั้งหมดใน context ได้แล้วครับ\nเอามันไปอยู่ร่วมกับ TestCase อื่น 👩‍👩‍👧‍👧 พอเรา Optimize Test Suite นี้จนไวขนาดนี้แล้วก็ได้เวลารัน Test Suite ทั้งหมดแล้ว ซึ่งพอเรารันครั้งแรกก็เจอปัญหาเลยครับ เพราะว่ามันไม่ได้เคลียร์ cookie ให้ ทำให้ Test Suite ที่เกี่ยวกับ Sign up จริงๆ พังหมดเลยเพราะ state มันไม่ได้เริ่มต้นที่ unauthenticate user\nความคิดแรกที่คิดคือ เราต้อง Clear Cookie ตอนรันจบ Test Suite นี้ ซึ่งสัญชาติญาณแรกคือมี before ก็ต้องมี after แต่พอเราเอาไปใส่ after เทพบอสคนเดิมก็ได้ให้คำแนะนำที่ดีมากมาอีกแล้วว่า\nถ้าเราเอา step clearCookie นี่ไปไว้ใน after ถ้า TestCase เราพังระหว่างทางแล้วใครจะเป็นคน clearCookie หล่ะ มันเลยควรจะไปอยู่ใน before ก่อนทุกๆ Step ใน TestSuite เรา จะเป็นการรับประกันว่ามันจะถูก clearCookie แน่นอนก่อนเริ่ม Test Suite นี้\nจากความรู้ตรงนี้ Test Suite สุดท้ายของเราเลยออกมาหน้าตาแบบนี้ครับ\ndescribe(\u0026#39;Pricing plan page\u0026#39;, () =\u0026gt; { context(\u0026#39;Product Plan Section\u0026#39;, () =\u0026gt; { before(() =\u0026gt; { cy.clearCookies() cy.login() }) beforeEach(() =\u0026gt; { Cypress.Cookies.preserveOnce(\u0026#39;sessionid\u0026#39;, \u0026#39;csrftoken\u0026#39;) cy.visit(\u0026#39;/plan\u0026#39;) }) it(\u0026#39;Should see Product title\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-title\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;Basic Plan\u0026#39;) }) it(\u0026#39;Should see price\u0026#39;, () =\u0026gt; { cy.get(\u0026#39;.plan-price\u0026#39;).should(\u0026#39;contain\u0026#39;, \u0026#39;$599\u0026#39;) }) }) }) Recap 🛡 ก่อนจะจบเรามาทวนกันก่อนครับว่าใน blog นี้เรารู้อะไรบ้าง\nใน E2E เราควรลด Operation ที่ใช้เวลานานให้น้อยที่สุดเราจะได้ Feedback อย่างรวดเร็ว Cypress มี beforeEach ให้ใช้กรุ๊ป command ที่เราต้องการรันก่อนทุก TestCase แต่ถ้าอยากรันครั้งเดียวใน Context จะมี command before ให้ เรารู้จักว่า Cypress จะจัดการเกี่ยวกับ Cookie ให้เราเสมอ ถ้าอยากเก็บ Cookie ไว้ให้ใช้ Cypress.Cookies.preserveOnce แต่ถ้าอยากลบให้ใช้ cy.clearCookies() ก็หวังว่า blog นี้จะมีประโยชน์นะครับสำหรับใครที่เริ่มรู้สึกว่า E2E รันช้าเหลือเกิน แล้วพบกันใหม่ครับ!\nOriginal post at: https://yothinix.medium.com/ใครว่า-e2e-เทสรันช้า-เทคนิคง่ายๆ-ที่จะทำให้-cypress-รันเร็วติดจรวด-6ef6cc775ca0\n","permalink":"https://yothinix-com.pages.dev/improve-cypress-test-performance/","summary":"\u003cp\u003eเกริ่นก่อนว่าที่ Pronto Tools เราเปลี่ยนมาใช้ Cypress มาได้ซักพักแล้วครับแล้วเราชอบมันมาก เราเลยไม่ลังเลเลยที่จะย้ายและเพิ่ม E2E เทสมาอยู่บน Cypress ซึ่งพอเทสมันเพิ่มขึ้นอย่างรวดเร็ว เวลาที่ใช้รันมันก็เพิ่มขึ้นอย่างมีนัยยะสำคัญ\u003c/p\u003e\n\u003ch1 id=\"ทำไม-e2e-เทสถงรนชา-\"\u003eทำไม E2E เทสถึงรันช้า 🐢\u003c/h1\u003e\n\u003cp\u003eปัญหาหลักเลยคือ E2E เทสจะค่อนข้างมี Step ที่ทำงานซ้ำๆ เกิดขึ้นบ่อยๆ เพื่อ Setup ข้อมูลให้พร้อมที่จะเทสใน TestCase หลัก ปัญหาหลักๆ ก็คืองานซ้ำๆ นั้นถ้ามันใช้เวลารันนาน ถ้ามันยิ่งมีจำนวนมากขึ้นก็จะยิ่งทำให้ชุดทดสอบเราทำงานช้าขึ้นเรื่อยๆ ลองมาดูตัวอย่างของเทสกันครับ\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003edescribe\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Pricing plan page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Product Plan Section\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Should see Product title\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esignUp\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evisit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;/plan\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;.plan-title\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003eshould\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;contain\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Basic Plan\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003eit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Should see price\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esignUp\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evisit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;/plan\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nx\"\u003ecy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;.plan-price\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003eshould\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;contain\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;$599\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eจากโค้ดตัวอย่างข้างต้น จะเป็นการเทสว่าหน้า Pricing Plan เราเนี่ยมันมีชื่อ Plan กับราคาอยู่ ซึ่งจะเห็นว่าการจะทดสอบ TestCase นึงนี่ เราต้องเสียเวลาไปรัน command cy.signUp() ซึ่งเป็น command ที่เราสร้างให้เอาไว้สมัครสมาชิกเข้า service เรา ซึ่งเวลาสมัครใช้งานเนี่ย มันจะมีการทำงานหลายอย่างเกิดขึ้นไม่ว่าจะเป็น สร้าง subscription user, ส่งอีเมล์ยืนยันการสมัคร, ฯลฯ แต่ละอย่างนี่ใช้เวลาทั้งนั้นครับ\u003c/p\u003e","title":"ใครว่า E2E เทสรันช้า เทคนิคง่ายๆ ที่จะทำให้ Cypress รันเร็วติดจรวด"},{"content":"ปีนี้โดยรวมเป็นปีที่ไม่ค่อยรู้สึกดีกับตัวเองเท่าไร และอยู่กับความรู้สึกแบบนั้นมาตลอดปี สิ่งสำคัญที่ได้เรียนรู้จากเรื่องราวทั้งหมดในปีที่ผ่านมาคือ ถ้าอยากทำอะไรแล้วทำไปเลย อย่ารอให้มันพร้อมแล้วค่อยทำ เพราะสิ่งที่รู้สึกไม่ค่อยดีทั้งหลายส่วนใหญ่ในปีนี้ก็เกิดจาก สุดท้ายมันจะไม่ได้ทำนี่แหละ\nFinance 💸 หลังจากปีที่แล้วทำการ Reset หนี้ทั้งหมดแล้วเริ่มต้นใหม่ สิ่งที่ได้เรียนรู้ปีนี้คือ ไม่มีหนี้อะดี แต่ไม่มีหนี้แล้วไม่มีตังค์อ่ะไม่ดี คือ ช่วงแรกๆ ยังติดใจความรู้สึกไม่มีหนี้อยู่ แต่พอเวลาผ่านไปเริ่มรู้สึกว่าทำไมเงินมันไม่ต่างจากเดิมเลย เป็นเพราะว่าถึงแม้จะเคลียร์หนี้หมด แต่การไม่ได้เก็บตังค์เพิ่มต่อ สุดท้ายมันก็เป็นการนับถอยหลังให้เงินหมดเหมือนเดิม\nปีนี้เลยเปลี่ยน Strategy ใหม่ประมาณกลางๆ ปีคือ มีหนี้อะมีได้ แต่ต้องเป็นหนี้ที่ควบคุมและรับความเสี่ยงได้ พอคิดอย่างนี้ เลยทำให้ชีวิตมันปลดล็อก ได้อะไรหลายๆ อย่างที่อยากได้มาตลอดใน Worth mention เดียวก็เห็น นอกจากนี้แล้วปีนี้ได้เปิดเลนการลงทุนใหม่ด้วย หลังจากศึกษามานาน ปีนี้จัดกองทุนรวมไป 3 กอง ถึงแม้ตอนนี้ยอดไม่เยอะ แต่ถ้าเป็นไปตามแผน มันก็จะอยู่ไปด้วยยาวๆ อีกหลายปี\nStudy 📚 ปีที่แล้วหัวข้อตรงนี้คือ Reading แต่ปีนี้อ่านหนังสือน้อยมาก อย่างมีนัยยะสำคัญ แต่สิ่งที่มากกว่าอ่านหนังสือคือ เรียนนี่แหละครับ และนี่คือคอร์สที่เรียนมาตลอดปีนี้\nNode.js + GraphQL + Apollo workshop Apache Kafka Workshop Android A-Z Modern Agile Development Workshop Brush lettering Workshop ส่วนหนังสือปีนี้ซื้อหลายเล่มแต่ที่จำได้หลักๆ มี Principle, Sapiens และ It doesn’t have to be crazy at work ส่วนพวกลิ้ง Technical Blog ปีนี้จัดการได้ดีขึ้นโดยแทนที่จะดองไว้ใน bookmark ซักที่ก็พยายามจะอ่านทุกลิ้งให้มันจบซักวันภายในอาทิตย์นั้น แต่สิ่งที่ Improve ที่สุดคือติดนิสัย Zero Inbox และเลิกอ่านเมล Medium Daily Digest นี่แหละ ที่ทำให้จัดการ Knowledge พวกนี้ได้อยู่หมัด\nWork 👨‍💻 ปีนี้เรียกได้ว่าเป็นปีที่ก่อตั้งหลายๆ อย่าง เริ่มจากต้นปี CoolBar ได้ถือกำเนิดขึ้น (ใช่ผมนับมันเป็นงาน) ซึ่งเกิดจากไอเดียที่คิดไวทำไวกับ Cory แล้วเกิดเป็น Bar ขึ้นมา กลางห้องทำงาน Pronto Tools ซึ่งตอนแรกเปิดทุกศุกร์ แต่เริ่มขี้เกียจเลยเป็นศุกร์ปิด Sprint แล้วกลายเป็นหายไปเลย แต่ถึงแม้ปัจจุบันจะไม่ค่อยได้เปิดบ่อยๆ แล้ว สิ่งหนึ่งที่ยังประทับใจอยู่ในความทรงจำทุกครั้งที่เปิด CoolBar คือบทสนทนาครับ หลายคนจากหลายๆ ทีมที่ไม่เคยมีโอกาสคุยด้วยก็ได้รู้จักมากขึ้น ได้แลกเปลี่ยนความคิดกันบางทีกลับเกือบตีสอง เป็นประสบการณ์ที่ไม่มีวันลืมเลย\nไม่ค่อยมีรูปถ่ายไว้เท่าไร แต่นี่น่าจะเป็น Coolbar ครั้งแรกๆ เลย\nต่อมาประมาณปลายเดือนมิถุนายน หลังจากแชร์ทุกอย่างเกี่ยวกับ Python ในเฟสตัวเองมาหลายปี แล้วรู้สึกอยากทำให้มีคนรู้จัก Python จริงๆ ที่ไม่ได้มองแค่เป็นภาษาที่เอาไว้ทำอะไรง่ายๆ แต่เป็นภาษาที่มีอัตราเติบโตสูงเพราะ eco-system มันดีจริงๆ ด้วยเหตุนี้เองเพจ เขียนงูให้วัวกลัว เลยถือกำเนิดขึ้นครับ\nช่วงทำเพจใหม่ๆ แนวทางยังค่อนข้างสะเปะสะปะมาก พยายามลองทำหลายๆ อย่างทั้ง #PythonNews, #PythonTricksEveryday แม้กระทั่ง Weekly Newsletter ก็ทำมาแล้ว ซึ่งที่พูดๆ มาเนี่ย ทำจนเหนื่อยจนหยุดพักไปหลายรอบเหมือนกัน สุดท้ายหลังๆ เลยทำแค่พอดีๆ คือถ้าอยากโพสก็โพส คือความอยากโพสมันมีอยู่ตลอดแหละ แต่ถ้ามากไปมันก็ไม่ค่อยดี เพราะมันต้องเตรียมข้อมูลด้วย\nภาพ Profile Page เวอร์ชั่นแรกๆ ซึ่งวาดในไอแพด จนถึงปัจจุบันก็ยังไม่รู้ว่าวัวตัวผู้หรือตัวเมีย\nแต่ถึงจะเหนื่อยมันก็คุ้มเพราะมันทำให้ได้ทำสิ่งที่อยากทำมากที่สุดและเป็นเป้าหมายของปีนี้ได้สำเร็จคือ มีโอกาสได้ไปสอน Python นี่แหละครับ และเป็นการสอนที่อยากจะทำมานานแล้วคือ ไม่มี Slide ทุกอย่างคือ สด และกลั่นออกมาจากประสบการณ์จริงๆ แต่ข้อเสียก็คือเนื้อหาก็สะเปะสะปะมากเหมือนกัน เพราะของที่มีมันเยอะ แต่ก็ดีใจที่ได้ช่วยทีมๆ นึงได้รู้จัก Python มากขึ้น\nCourse Python for sustainable code base รุ่นแรก ที่ INET\nนอกจากจะเปิด Course เองแล้วยังได้ไปช่วยสอนที่ Django Girls Bangkok ด้วย\nสิ่งสุดท้ายที่ก่อตั้งในปีนี้คือ CheckUp ครับเป็น Internal event ใน ProntoTools เกิดจากไอเดียง่ายๆ ว่าหลายอย่างเราเคยทำ แต่บางครั้งเราไม่เคยทำมันบ่อยๆ เราก็ลืม โดยกฏของ CheckUp มีแค่ 2 ข้อครับ\nใครอยากจัดอะไรก็สร้างปฏิทินจองไว้เลย จองก่อนได้ก่อนง่ายๆ แบบนี้เลย คนที่จองต้องเป็นคนสรุปเนื้อหาที่คุยกันใน CheckUp ไว้ใน Pronto Cafe (Internal Forum) เพื่อที่จะให้คนที่ไม่มีโอกาสได้มา ได้เข้าถึงเนื้อหาที่เราคุยกันด้วยครับ ข้อเสียเดียวของ CheckUp คือมันมาเริ่มก่อตั้งในช่วงที่งานยุ่งสุดๆ คือช่วงท้ายปีครับ ทำให้เรามีโอกาสจัดกันจริงๆ ประมาณ 4 ครั้ง เองก็ได้แต่หวังว่าปีหน้าจะมีโอกาสมาจัดกันมากขึ้น\nCheckUp: Python\nนอกจากก่อตั้งงานหลักๆ ปีนี้ก็ค่อนข้างจะหลากหลาย มีโอกาสได้ Upgrade Production เป็น Python 3.7 ซึ่งสามารถอ่านเพิ่มเติมได้ตามลิ้งข้างล่างเลยครับ\nShare ประสบการณ์ Upgrade Python 3.7 ถ้าจะมีงานหนึ่งที่ผมทำแล้วรู้สึกสนุกและท้าทายทุกครั้งที่อยู่ที่ Pronto Tools ก็คือการอัพเกรดเวอร์ชั่น Python นี่แหละครับ ตอนผมเข้ามาทำงานใหม่ๆ ทีมใช้ Python 3.5 อยู่ปีที่แล้วเลยอัพเกรดเป็น 3.6 และในปีนี้เนื่องในโอกาส Python 3.7 — Yothinix, Yothin Muangsommuk\nแต่ถ้าจะมีอะไรทำลายสถิติอีกปีนี้ คือเป็นปีที่ Hackathon บ่อยมากทั้งใน Pronto Tools เองและนอกสถานที่ ต้องขอบคุณ\nKan Ouivirachที่พยายามสร้าง Hackathon culture ขึ้นมาเลยได้สร้างอะไรเจ๋งๆ ได้ลองอะไรหลายๆ อย่างตั้งแต่ Elixir, Scala ไปจนถึง GraphQL แต่สำคัญที่สุดคือ ได้เขียนโค้ดแบบสนุกๆ นี่แหละ\nHackathon ครั้งสุดท้ายของปี 2018\nTravel ⛰ ปีนี้เริ่มปีด้วยเป็นมนุษย์เร่ร่อนตั้งแต่ไปเที่ยวเชียงใหม่กับตั๊กแล้วยังไม่ทันได้กลับบ้านต้องบินลงไปนครศรีธรรมราชต่อเพื่อไปช่วยจัด Hackathon ต่อ\nต้องโน๊ตไว้ว่าไปเชียงใหม่รอบนี้ Improvise มากคือ เปิด map เลยไปที่ๆ ไม่เคยไป แล้วประทับใจมากทั้ง North Gate และร้านลับในนิมมาน จนปี 2019 ต้องกลับไปอีก ส่วนนครศรีธรรมราชซึ่งเป็นครั้งแรกในชีวิตที่ได้ไป ก็ได้รู้จักกับร้านพี่แหลม แห่งท่าศาลา ก็เป็นประสบการณ์ที่แปลกดี\n4 Land ภายในอาทิตย์เดียว 2 Land ในนั้นเป็นเครื่องลำเดียวกัน (HS-DBC) 1 Land ในนั้นติด Holding\nอีกเรื่องนึงทีต้องโน๊ตไว้คือปีนี้เป็นปีแรกที่ได้ไป Outing กับ Pronto ซึ่งเป็นครั้งที่สองในชีวิตที่เริ่มได้ไป Outing จริงๆ คือทำงานปีที่สองในบริษัท (ตอนอยู่ที่เก่าก็ต้องรอปีที่สองถึงได้ไป Outing เหมือนกัน) แล้วเป็น Outing ที่มีกิจกรรมต้องทำเยอะ ต้องซ้อมละคร ต้องเล่นเกม ฯลฯ แต่ก็สนุกไปอีกแบบ\nLife 😅 ปีนี้เริ่มปีด้วยในที่สุดก็ไปยกเลิก WE Fitness ที่เอกมัยหลังจากจ่ายค่าสมาชิกรายเดือนมาเกือบหนึ่งปีแล้วแทบไม่ได้ไปเลย แต่หลังจากนั้นอีก 7 เดือนก็ตัดสินใจเดินเข้า WE Fitness อีกครั้งแต่ครั้งนี้เป็นสาขารัชโยธินและตัดสินใจสมัครเลยพร้อมเทรนเนอร์อีก 50 Sessions ถึงตอนที่เขียนนี่ก็ออกกำลังกายมา 4 เดือนแล้ว ยังจำความรู้สึกที่กลับไปออกวันแรกได้เป็นอย่างดี\nสวัสดี #นิวแมน วันแรก\nถึงแม้วันแรกจะแทบคลานกลับคอนโด แต่ถ้ามองย้อนกลับไปก็เป็นการลงทุนที่คุ้มค่าที่สุดของปีนี้ละ เพราะหลังจากนั้นอีกสองสามเดือน พอมา Cardio ชุดเดียวกันกับที่ทำวันแรก มันก็เหนื่อยนะ แต่มันไม่ถึงกับแทบคลานเหมือนตอนนั้นอีกแล้วต้องขอบคุณเติ้ลมากๆ ที่สร้าง #นิวแมน เวอร์ชั่นใหม่มาได้ขนาดนี้ 👏\nนอกจากจะแข็งแรงขึ้นปีนี้ยังแอดมิทโรงพยาบาล 1 ครั้งด้วย หลังกลับมาจาก Outing ไม่กี่วันซึ่งอยู่ดีๆ ก็รู้สึกปวดแปลบที่ข้างเอวๆ ตอนแรกก็กลัวว่าไส้ติ่งรึเปล่าเพราะไม่เคยเป็นมาก่อนในชีวิต แต่พอไปหาหมอสรุปสาเหตุว่าเป็นลำไส้อักเสบ ต้องนอนให้ยาเลยคืนนึง หลังจากดื้อไม่ยอมแอดมิทวันแรกที่ไปเพราะค่าห้อง ร.พ.พญาไท 2 ไม่ธรรมดานะครับ และถึงแม้ว่าจะมีประกันกลุ่มบริษัทช่วยไว้นิดหน่อย แต่นี่ก็เป็นเครื่องยืนยันอันดีว่าควรจะหาประกันสุขภาพของตัวเองไว้ด้วย\nและที่เปลี่ยนแปลงที่สุดในหมวดนี้คงหนีไม่พ้นย้ายจากการเป็นมนุษย์เอกมัยมา 4 ปี มาเป็นมนุษย์จตุจักรและได้รู้จักกับคำว่าห้าแยกลาดพร้าว แต่ถึงแม้ว่าเวลาเดินทางจะไม่ได้เปลี่ยนมาก แต่การเปลี่ยนมาอยู่คอนโดนี่ก็เปิดหลายๆ เลนในชีวิตและทำให้รู้ว่าการทำกับข้าวกินเองอยู่คอนโดนี่มีความสุขที่สุดละ (ยกเว้นตอนล้างจาน)\nลาก่อยแจ่มจันทร์อพาร์ตเม้นต์ที่อยู่มาตั้งแต่เรียนจบ\nWorth mention 🤔 ปีนี้มีโอกาสพูดงาน Conference ครั้งเดียวแต่เป็นหนึ่งครั้งที่ดีใจมากคือ PyCon Thailand 2018 บอกเลยว่าปั่นสไลด์สดหนึ่งคืนก่อนพูด แต่มันก็ไม่ได้สดขนาดนั้นเพราะจริงๆ ก็เคยเขียนบล็อกเรื่องนี้ไว้แล้วตั้งแต่เดือนมีนาคม Python Type Annotation: ทำไม Python ต้องเขียน Type ด้วย ตั้งแต่ Python 3.5 เป็นต้นมา Python ได้แปลงร่างจากภาษา Duck Typing เต็มตัว ให้มีความสามารถในการใส่ Type Annotation… — Medium, Yothin Muangsommuk\nปีนี้ดูมหรสพ 3 ครั้ง 2 ครั้งในนั้นเป็นถาปัดการละคอน แดจังกึม กับ Anastasia อีกหนึ่งครั้งคือตั๊กลากไปดูคอนน้อง Phum Viphurit ซึ่งหลังจากตั๊กกล้าแกร่งแล้วปีหน้าเลยตัดสินใจไปดู 1975 ข้ามประเทศเลยทีเดียว ปีนี้เล่นเกมส์เยอะมากเริ่มจาก The Sims mobile, Take On: Helicopter, Harry Potter: Hogwarts Mystery, Star Wars: Force Arena, Fallout Shelter, Motor Sport Manager 3, Far Cry 5, Call of Duty: Advanced Warfare แล้วมาจบที่ Assassin’s Creed: Origins หลังจากแกล้งตั๊กทุกวันว่า เด๋ววันนี้ซื้อ PS4 เลย มาเดือนกว่า พอไปซื้อจริงๆ นี่ไม่เขินเลย\nตอนช่วงเดือนธันวาคม 2017 จนถึงมกราคม 2018 ตื่นเช้ามาแล้วเจ็บคอบ่อยมาก หรือไม่ก็เจ็บจนตื่นกลางดึก เลยตัดสินใจซื้อเครื่องฟอกอากาศมาใช้ แล้วเป็นการลงทุนที่คุ้มมากเพราะหลับสนิทเลย ยิ่งช่วงปีที่ผ่านมามีช่วงที่อากาศกรุงเทพไม่ดีถึงสองรอบ เลยรู้สึกคิดถูกมากที่ซื้อไว้ ปีนี้เริ่มต้นปีตั้งใจไว้ว่าจะใช้สมุดทำ Bullet Journaling หลังจากใช้ไปหลายเดือนแล้วเลยกลั่นออกมาเป็น Blog นี้ซึ่งคนอ่านหลักหมื่น (อันนี้เซอร์ไพรซ์มาก) แนะนำ BuJo เมื่อชีวิตอยากติด Analog มันมีสิ่งหนึ่งที่ผมสงสัยมานานหลายปีละว่าทำไมหลายคนถึงติดสมุด Moleskine มากๆ ทั้งๆ ที่มันก็ดูเหมือนสมุดธรรมดาๆ เล่มนึง ที่อาจจะมีเส้น ไม่มีเส้น เป็นตาราง ฯลฯ หลังจากถามไถ่หลายคนก็ยังไม่เคลียร์เพื่อคลายความสงสัยนั้น ผมเลยซื้อมาหนึ — Yothinix, Yothin Muangsommuk\nแต่หลังจากใช้สมุดเป็นหลักมาหลายเดือน iPad 6th Generation ก็ออกแล้วใช้ Apple Pencil ได้และเป็นสมุดหลักมาจนถึงทุกวันนี้ ถึงแม้ว่าระหว่างปีจะสลับไปใช้ Trello, Todoist บ้าง แต่การกลับมาเขียนนี่แหละดีที่สุดละ และแอพ GoodNote นี่มันดีจริงๆ\nสิ่งแรกๆ ที่ทำหลังจากได้ ipad มาคือพยายาม Setup มันให้เขียนโปรแกรมได้\nหลังจากดู R Willy เล่น Scooter ใน IG มาพักใหญ่ ไม่รู้จับพลัดจับพลูยังไง ถึงไปรู้จัก Street League Skateboard ได้ ซึ่งทำให้บ้า SLS มาตั้งแต่กลางๆ ปี แล้วก็ติดช่อง Braille Skateboarding มาก จนวันนึงไป Preduce แล้วได้ Skateboard กลับบ้านมา ผ่านมา 6 เดือนขอสารภาพเลยว่ายัง Ollie ไม่ได้ Insanity มาก รู้ตัวอีกทีก็กลับบ้านมาพร้อมสิ่งนี้ละ\nปีนี้ไปงานวิ่ง 1 งานถ้วนคือ ร่มรั้วรัน สิ่งที่เจ๋งที่สุดของร่มรั้วรันไม่ใช่กลับไปวิ่งลาดกระบัง แต่คือได้เจอเพื่อนที่ไม่ได้เจอมาหลายปีนี่แหละ คิดถึงจริงๆ ปีนี้ดู Star Trek: The Next Generation จบแล้ว ต้องบอกว่าจบตั้งแต่กลางๆ ปีแล้วรวมเวลาเป็นเกือบ 2 ปียกให้เป็น Generation ของ Star Trek ที่ชอบที่สุดละเพราะ 7 Seasons นี่ผูกพันธ์กับตัวละครมาก หลังจากนั้นพยายามดู DS9 แล้วแต่ไม่สนุกเลย เลยข้ามมาดู Voyager อยู่ พูดถึงซีรีย์ต่อละกันปีนี้เป็นปีที่กลับมาดูซีรีย์เยอะมาก (หลังจากปีที่แล้วดูแต่ Star Trek: TNG เป็นหลัก) ซีรีย์ที่ดูหลากหลายมากตั้งแต่ Star Trek: Discovery, Designated Survivor, Stranger Things, How I Met Your Mother, Agent of Shield, A very secret service อ่อแล้วที่ต้องโน๊ตไว้คือ เลือดข้นคนจาง ปีนี้ตั๊กยังทำลายสถิติทุกอย่างของโยธินต่อไป แต่ความซวยของปี 2018 คือลืมวันเกิดตั๊กนี่แหละ ปีหน้าจะไม่ลืมแล้วคาบ 🙏 หมดละปีนี้ ถ้าจะมีอะไรที่ดีมากๆ เกี่ยวกับปี 2018 คือการไม่ตั้ง New Year Resolution พร่ำเพรื่อ นี่แหละ สุดท้ายการตั้งเป้าหมายต้นปีมันไม่ได้มีประโยชน์อะไรเลย แต่การได้ทำมันระหว่างที่เราเดินทางในปีนั้นนี่แหละคือสิ่งสำคัญที่สุดละ\nOriginal post at: https://yothinix.medium.com/2018-4e68fb381d78\n","permalink":"https://yothinix-com.pages.dev/2018/","summary":"\u003cp\u003eปีนี้โดยรวมเป็นปีที่ไม่ค่อยรู้สึกดีกับตัวเองเท่าไร และอยู่กับความรู้สึกแบบนั้นมาตลอดปี สิ่งสำคัญที่ได้เรียนรู้จากเรื่องราวทั้งหมดในปีที่ผ่านมาคือ \u003cem\u003eถ้าอยากทำอะไรแล้วทำไปเลย อย่ารอให้มันพร้อมแล้วค่อยทำ\u003c/em\u003e เพราะสิ่งที่รู้สึกไม่ค่อยดีทั้งหลายส่วนใหญ่ในปีนี้ก็เกิดจาก สุดท้ายมันจะไม่ได้ทำนี่แหละ\u003c/p\u003e\n\u003ch1 id=\"finance-\"\u003eFinance 💸\u003c/h1\u003e\n\u003cp\u003eหลังจากปีที่แล้วทำการ Reset หนี้ทั้งหมดแล้วเริ่มต้นใหม่ สิ่งที่ได้เรียนรู้ปีนี้คือ \u003cem\u003eไม่มีหนี้อะดี แต่ไม่มีหนี้แล้วไม่มีตังค์อ่ะไม่ดี\u003c/em\u003e คือ ช่วงแรกๆ ยังติดใจความรู้สึกไม่มีหนี้อยู่ แต่พอเวลาผ่านไปเริ่มรู้สึกว่าทำไมเงินมันไม่ต่างจากเดิมเลย เป็นเพราะว่าถึงแม้จะเคลียร์หนี้หมด แต่การไม่ได้เก็บตังค์เพิ่มต่อ สุดท้ายมันก็เป็นการนับถอยหลังให้เงินหมดเหมือนเดิม\u003c/p\u003e\n\u003cp\u003eปีนี้เลยเปลี่ยน Strategy ใหม่ประมาณกลางๆ ปีคือ \u003cem\u003eมีหนี้อะมีได้ แต่ต้องเป็นหนี้ที่ควบคุมและรับความเสี่ยงได้\u003c/em\u003e พอคิดอย่างนี้ เลยทำให้ชีวิตมันปลดล็อก ได้อะไรหลายๆ อย่างที่อยากได้มาตลอดใน \u003cstrong\u003eWorth mention\u003c/strong\u003e เดียวก็เห็น นอกจากนี้แล้วปีนี้ได้เปิดเลนการลงทุนใหม่ด้วย หลังจากศึกษามานาน ปีนี้จัดกองทุนรวมไป 3 กอง ถึงแม้ตอนนี้ยอดไม่เยอะ แต่ถ้าเป็นไปตามแผน มันก็จะอยู่ไปด้วยยาวๆ อีกหลายปี\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/2018/1-EWXyaOb7uyXEw3ia7fZapg_hu_dfe2846981b478e8.webp\"\n       srcset=\"/2018/1-EWXyaOb7uyXEw3ia7fZapg_hu_dfe2846981b478e8.webp 360w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"360\" height=\"360\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003ch1 id=\"study-\"\u003eStudy 📚\u003c/h1\u003e\n\u003cp\u003eปีที่แล้วหัวข้อตรงนี้คือ \u003cem\u003eReading\u003c/em\u003e แต่ปีนี้อ่านหนังสือน้อยมาก อย่างมีนัยยะสำคัญ แต่สิ่งที่มากกว่าอ่านหนังสือคือ \u003cstrong\u003eเรียน\u003c/strong\u003eนี่แหละครับ และนี่คือคอร์สที่เรียนมาตลอดปีนี้\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eNode.js + GraphQL + Apollo workshop\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eApache Kafka Workshop\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAndroid A-Z\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eModern Agile Development Workshop\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eBrush lettering Workshop\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eส่วนหนังสือปีนี้ซื้อหลายเล่มแต่ที่จำได้หลักๆ มี Principle, Sapiens และ It doesn’t have to be crazy at work ส่วนพวกลิ้ง Technical Blog ปีนี้จัดการได้ดีขึ้นโดยแทนที่จะดองไว้ใน bookmark ซักที่ก็พยายามจะอ่านทุกลิ้งให้มันจบซักวันภายในอาทิตย์นั้น แต่สิ่งที่ Improve ที่สุดคือติดนิสัย \u003cstrong\u003eZero Inbox\u003c/strong\u003e และเลิกอ่านเมล \u003cem\u003eMedium Daily Digest\u003c/em\u003e นี่แหละ ที่ทำให้จัดการ Knowledge พวกนี้ได้อยู่หมัด\u003c/p\u003e","title":"2018"},{"content":"เป็นธรรมเนียมที่พึ่งสร้างเป็นปีที่สองกันครับว่า เราจะมามองย้อนกลับไปในปี 2018 ที่กำลังจะผ่านพ้นไปว่า Python Libraries ตัวไหนที่เราชอบบ้าง ของปีที่แล้วเราคัดมา 10 Libraries ปีนี้เราก็จะคัดมาอีก 10 เหมือนกันครับ แต่ลำดับไม่มีผลอะไรนะครับ ไปดูกันเลย\nSource: https://github.com/ambv/black\n\\1. Black — The uncompromising code formatter Source: https://github.com/ambv/black\nในสมัยก่อนพอพูดถึง Formatter ของ Python เราจะนึกถึงแค่ yapf เป็นหลัก รองลงมาก็ autopep8 ซึ่งก็มีฐานผู้ใช้ระดับนึง ปีนี้เรามีเจ้าใหม่เข้ามาในตลาดครับ ซึ่งก็คือ Black นี่เอง\nจุดเด่นของ Black คือ just work ครับลงปั๊ปใช้ได้เลย หรือถ้าอยากจะ config ก็ได้นิดหน่อย อีกจุดเด่นที่ทุกคนที่ได้ลองใช้ Black พูดถึงและมีทั้งชอบและไม่ชอบคือใช้ double quotes (“) มากกว่า single quotes (‘) ครับ แต่หลายๆ คนพอใช้แล้วก็ยังพิมพ์ single quotes เหมือนเดิมรวมทั้งผมด้วย แล้วปล่อยให้ Black มันจัดการไปครับ นอกจากนั้นแล้วตัว Black ยัง Optimize ให้ใช้กับ syntax ใหม่ๆ ที่มีใน Python 3.6+ และ stub file สำหรับเขียน type signature ของ function ด้วยครับ\nในปีที่ผ่านมาหลายๆ OSS โปรเจ็คได้ adopt Black เป็น codestyle (ล่าสุดก็ Hypothesis ครับ) สำหรับใครที่ลังเลอยู่ Black ก็มี playground ให้ลองเล่นนะครับ เผื่อจะช่วยให้ตัดสินใจง่ายขึ้น\nSource: https://github.com/tonybaloney/wily\n\\2. Wily — A command-line application for tracking, reporting on complexity of Python tests and applications Source: https://github.com/tonybaloney/wily\nCode complexity เป็นเรื่องหนึ่งที่ถูกหยิบขึ้นมาคุยใน Code Review บ่อยครับ แต่หลายๆ ครั้งเราไม่ค่อยมี proof เท่าไร และมักจะเป็นความรู้สึกมากกว่า Wily จะเข้ามาช่วยเราแก้ปัญหาในเรื่องนี้ครับ\nWily เป็น Library ที่ช่วยเราอ่าน Complexity ของ Code แล้วสร้าง report ให้เราครับ ความเจ๋งคือมันสร้าง report ได้เยอะมากตั้งแต่ command line output ยัน html graph เลยครับ โดย Metric ที่ Wily ดูมีตั้งแต่ Line of code, Cyclomatic complexity ไปจนถึง Maintainability index เลยครับ\nก่อนหน้านี้มี Library ที่วัด Metric code อยู่ครับคือ Radon กับ pylama แต่ปฏิเสธไม่ได้จริงๆ ว่า report กับ Statistic feature ของ Wily นี่มัน Game changer จริงๆ\nsource: https://github.com/benfred/py-spy\n\\3. py-spy — A sampling profiler for Python program Source: https://github.com/benfred/py-spy\nปัญหา Optimization เป็นปัญหานึงที่เราชาว Developer ต้องเจอกันเป็นประจำใช่มั้ยครับ แต่ก่อนเราจะ Optimize อะไรซักอย่างเราต้อง Measure มันให้ได้ก่อน ซึ่งวิธีการ Measure ก็มีหลายแบบโดยอาจจะไปแปะๆ log time เอาไว้ แต่ถ้ามันช้าใน Production หละการจะไปแปะๆ log time เอาไว้มันก็ทำไม่ได้เลยใช่มั้ยครับ นั่นแหละครับคือสิ่งที่ py-spy มาแก้ให้เรา\npy-spy ก็เป็น Profiler อีกตัวนึงครับ ความเจ๋งของมันก็คือ เราไม่ต้องแก้ code อะไรเลยเราสามารถจะ profiling ตัว Python process ที่กำลังรันอยู่หรือจะรัน script ผ่าน py-spy ก็ได้ครับ ซึ่งตัว py-spy จะ provide interface คล้ายๆ กับ top ที่เราคุ้นเคยกันเพื่อแสดงว่า function/method ไหนที่กินเวลาเรามากที่สุดครับ\nSource: https://itsdangerous.palletsprojects.com/en/1.1.x/\n\\4. itsdangerous — Various helpers to pass trusted data to untrusted environments and back. Source: https://github.com/pallets/itsdangerous\nโลกนี้อยู่ยากครับ ยิ่งต้องส่งข้อมูลไปมาผ่าน network ยิ่งต้องสันนิษฐานว่ามีโอกาสที่จะมีคนมาเปิดข้อมูล เลยทำให้เราต้องหาวิธีที่จะป้องกันไม่ให้คนเปิดข้อมูลสำคัญๆ นั้นได้ซึ่งส่วนใหญ่ก็เข้ารหัสกัน แต่จะทำยังไงก่อนหน้านี้ถ้าต้องทำอะไรแนวๆ นี้เราก็จะ implement เองซะส่วนใหญ่ครับจาก tools ที่ standard library มีให้เอามาประกอบๆ กัน แต่ตอนนี้เรามีคนทำให้แล้วครับ\nitsdangerous เป็น set ของ utils ที่ช่วยเราเข้า/ถอดรหัสข้อมูลที่ sensitive ครับโดยใช้ HMAC / SHA-512 เป็นตัว sign message ของเรา ตัว library ได้แรงบันดาลใจมาจาก Django’s signing module เพราะฉะนั้น API เลยค่อนข้างจะคล้ายๆ กันมากครับ นอกจากนั้นแล้วยังรองรับมาตรฐาน JSON Web Signature ด้วยครับ\nSource: https://github.com/sdispater/poetry\n\\5. Poetry — Dependency Management for Python Source: https://github.com/sdispater/poetry\nปีนี้ถ้าจะไม่พูดถึง Poetry ก็เหมือนจะขาดอะไรไป อย่างหลังจากปีที่แล้ว pipenv ได้ครองตลาดไปและ PyPI แนะนำว่าเป็น Package management ที่ควรใช้ แต่สำหรับคนที่ใช้ pipenv มาซักระยะจะเจอปัญหาที่สำคัญอย่างนึงคือ มันช้าครับ ตอนสร้าง Lockfile ค่อนข้างจะช้ามาก แต่นอกจากปัญหาฝั่ง user แล้วในส่วนของ pipenv เองนั้นก็ค่อนข้างจะซับซ้อนขึ้นเรื่อยๆ จน scale ยากครับ ผู้ท้าชิงตำแหน่งนี้ของปีนี้คือ Poetry ครับ\nPoetry เห็นข้อเสียหลายๆ อย่างของ pipenv และนำเสนอแนวทางใหม่ในการจัดการ dependencies ครับ โดย Poetry เลือกที่จะใช้ pyproject.toml ตามมาตรฐาน PEP 518 เป็นไฟล์หลักและมี poetry.lock เพิ่มขึ้นมาครับ ตัว Interface CLI นอกจาก add / install / update / remove มาตรฐานแล้ว ก็ยัง provide interface สำหรับจัดการ package ขึ้น PyPI ด้วยครับ build หรือ publish หรือสร้าง virtualenv ให้สำหรับ local environment ก็มีครับและที่สำคัญที่สุด generate lock ไฟล์เร็วมาก\nถ้าใครใช้ pipenv แล้วรู้สึกเหนื่อยๆ อืดๆ ลองเปลี่ยนมาใช้ poetry ดูครับโลกจะเปลี่ยนไปมากเลย\nSource: https://github.com/kennethreitz/responder\n\\6. Responder — a familiar HTTP Service Framework for Python Source: https://python-responder.org/en/latest/\nหลังจากปีที่แล้ว Kenneth Reitz ได้ทำให้โลกรู้จักกับ pipenv ไปแล้ว ปีนี้เค้ากลับมากับ responder ครับ (และ Bruce ที่ค่อยๆ เงียบหายไป)\nตัว Responder ดึงจุดเด่นจาก Framework อื่นมาเช่น Route แบบ Flask, Mutate Request/Response cycle แบบ Falcon, รองรับ WSGI interface และ ASGI interface ผ่าน Starlette, รองรับ graphQL ผ่าน graphene, รองรับ OpenAPI Schema ฯลฯ เรียกได้ว่า Interface สมัยใหม่ของ webservice แทบจะรองรับหมดแล้วครับสำหรับ Framework ตัวนี้\n\\7. Cursive_re — Readable regular expressions for Python 3.6 and up. Source: https://github.com/Bogdanp/cursive_re\nเขียน Regular Expression เป็นเรื่องยากครับ จะเขียนทีก็ต้องมาเปิด Document ทีว่าเขียนยังไง บางทีขี้เกียจเขียนก็ search หาเอาก็มี ปีนี้ผมผ่านไปเจอ cursive_re ครับและจะทำให้ชีวิตการเขียน Regular expression ของเราง่ายขึ้น\nตัว cursive_re จะแทนที่ Regular Expression syntax เราด้วย set ของ utils function ที่เราสามารถจะ compose ออกมาเป็น regular expression ได้ครับ ก็ช่วยให้เขียน pattern matching ง่ายขึ้นนิดหน่อย\nSource: https://github.com/Delgan/loguru\n\\8. Loguru — Python logging made (stupidly) simple Source: https://github.com/Delgan/loguru\nหลายๆ ครั้งใน Program เราต้องมีการใส่ log ไว้ใช่มั้ยครับ จุดประสงค์หลักคือเพื่อให้การ debug หรือ monitor ภายหลังสะดวกขึ้น ซึ่งตัว Python เองก็มี Standard library — Logging ไว้ให้อยู่แล้ว แต่โดยตัวมันเองถ้าไม่ config อะไรเลยก็ทำงานไม่ค่อยต่างจาก print() ฟังก์ชั่นเท่าไร\nตัว Loguru เป็น utils เล็กๆ ที่ provide interface ที่เราจะพ่น Log ไว้ให้ผ่าน logger function ที่เราเอาไปแปะไว้ใน function / class method ที่ต้องการครับ โดยตัว loguru จะสร้าง default format มาให้ out of the box เลยซึ่งจะเพิ่ม วันเวลา และ function ที่ execute ออกมาให้ด้วยนอกจาก message ครับ แต่ที่ซื้อผมได้มากที่สุดนี่คือมันมีสีนี่แหละทำให้ log มันน่าอ่านขึ้นมากครับ นอกจากนั้นแล้วตัว exception มันยังสามารถเปิดให้ catch value ของ variable ไว้ได้ด้วยครับ มีประโยชน์มากในการ debug ต่อไป\nSource: https://pyre-check.org/\n\\9. Pyre — A performant type-checker for Python 3 Source: https://pyre-check.org/\nโลกของ Typing ใน Python ก็ยังมีพัฒนาการเรื่อยๆ ครับ ปีที่แล้วเราเจอ MonkeyType จาก Instagram ที่ช่วย generate type signature ให้เราโดยที่เราไม่ต้องไปไล่เขียนทุกไฟล์เอง ในปีนี้เรามี Pyre จาก Facebook (ซึ่งน่าจะมาจากทีมเดียวกัน) และมันน่าสนใจมากเลยทีเดียว\nPyre เป็น Type checker เช่นเดียวกับ mypy ครับ ซึ่งทางทีมโฆษณาไว้ว่าเร็วกว่า mypy มากๆ เพราะมันจะเช็คแค่ dependencies ที่เกี่ยวกับโค้ดที่แก้ นอกจากนั้นแล้วยังรองรับ Watchman ซึ่งเป็น file watcher ที่ Facebook พัฒนาขึ้นทำให้เราแทบจะ automate การรัน type checker ได้เลย\n\\10. Responses — A utility for mocking out the Python Requests library Source: https://github.com/getsentry/responses\nResponses อาจจะไม่ใช้ Library ที่เกิดในปีนี้ แต่เป็น Library ที่เราค้นพบในปีนี้ที่เปลี่ยนวิธีการเขียนเทสของทีมไปเลย ซึ่งก่อนหน้านี้เราก็เคยเขียนบล็อกอธิบายความดีงามของมันไปแล้ว แต่ถ้าใครยังไม่เคยอ่านก็ตามไปที่ลิ้งข้างล่างเลยครับ\nMock requests แบบสวยๆ ด้วย responses สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ สมมติเรามีฟังก์ — Yothinix, Yothin Muangsommuk\nWorth mentioning ยังมี Package อีกหลายตัวครับที่เราชอบ แต่เราจะไม่ลงรายละเอียดมากก็จะขอ List ไว้ตรงนี้ละกันครับ\nปีที่ผ่านมานอกจาก Responder แล้วยังมี API Framework เกิดขึ้นมาอีกหลายตัวครับ ที่อาศัย async ในการเพิ่มความเร็ว service ซึ่งมีสองสามตัวที่น่าสนใจมากที่เกิดขึ้นในปีนี้คือ molten กับ Vibora ครับ และที่ไม่พูดถึงไม่ได้เลยคือ Starlette ครับ จะเห็นว่า Trend package ที่ชอบปีนี้ส่วนใหญ่มาในแนว utils เล็กๆ ซึ่งช่วยให้งานใหญ่ๆ เราทำงานง่ายขึ้น มีอีกหลายตัวที่ผมคัดมาแต่ไม่ได้พูดถึงเพราะซ้ำแนวกัน อย่างเช่น Logme ที่เอาไว้ใช้แทน logger แต่ก็แพ้ความสามารถของ Loguru ไป เป็นต้น Pampy — เป็น Library ไว้ทำ Pattern matching อันนี้เพิ่งออกมาได้ไม่กี่นาน แต่ดูดีเลยทีเดียว มีเก็บไว้ในคลังเอาไว้แก้โจทย์ algorithm ได้ Original post at: https://yothinix.medium.com/10-python-libraries-ที่เราชอบในปี-2018-2b003ada90d4\n","permalink":"https://yothinix-com.pages.dev/10-python-libraries-we-like-2018/","summary":"\u003cp\u003eเป็นธรรมเนียมที่พึ่งสร้างเป็นปีที่สองกันครับว่า เราจะมามองย้อนกลับไปในปี 2018 ที่กำลังจะผ่านพ้นไปว่า Python Libraries ตัวไหนที่เราชอบบ้าง \u003ca href=\"/10-python-libraries-we-like-2017/\"\u003eของปีที่แล้วเราคัดมา 10 Libraries\u003c/a\u003e ปีนี้เราก็จะคัดมาอีก 10 เหมือนกันครับ แต่ลำดับไม่มีผลอะไรนะครับ ไปดูกันเลย\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp\"\n       srcset=\"/10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_8b8e0a7608b29e28.webp 480w, /10-python-libraries-we-like-2018/0-4sRfrH8NrmrgqQIm_hu_1b3907a1451dd553.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"352\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eSource: \u003ca href=\"https://github.com/ambv/black\"\u003ehttps://github.com/ambv/black\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003ch1 id=\"1-black--the-uncompromising-code-formatter\"\u003e\\1. Black — The uncompromising code formatter\u003c/h1\u003e\n\u003cp\u003eSource: \u003ca href=\"https://github.com/ambv/black\"\u003ehttps://github.com/ambv/black\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eในสมัยก่อนพอพูดถึง Formatter ของ Python เราจะนึกถึงแค่ \u003ca href=\"https://github.com/google/yapf\"\u003eyapf\u003c/a\u003e เป็นหลัก รองลงมาก็ \u003ca href=\"https://pypi.org/project/autopep8/\"\u003eautopep8\u003c/a\u003e ซึ่งก็มีฐานผู้ใช้ระดับนึง ปีนี้เรามีเจ้าใหม่เข้ามาในตลาดครับ ซึ่งก็คือ Black นี่เอง\u003c/p\u003e\n\u003cp\u003eจุดเด่นของ Black คือ just work ครับลงปั๊ปใช้ได้เลย หรือถ้าอยากจะ config ก็ได้นิดหน่อย อีกจุดเด่นที่ทุกคนที่ได้ลองใช้ Black พูดถึงและมีทั้งชอบและไม่ชอบคือใช้ double quotes (“) มากกว่า single quotes (‘) ครับ แต่หลายๆ คนพอใช้แล้วก็ยังพิมพ์ single quotes เหมือนเดิมรวมทั้งผมด้วย แล้วปล่อยให้ Black มันจัดการไปครับ นอกจากนั้นแล้วตัว Black ยัง Optimize ให้ใช้กับ syntax ใหม่ๆ ที่มีใน Python 3.6+ และ stub file สำหรับเขียน type signature ของ function ด้วยครับ\u003c/p\u003e","title":"10 Python libraries ที่เราชอบในปี 2018"},{"content":"อย่างที่ทุกคนรู้นะครับว่า Guido ได้ถอดตัวออกจากการเป็น BDFL Role ที่เป็นมาอย่างยาวนานในช่วงกลางปีที่ผ่านมา แล้วการออกนั้นถึงแม้จะไม่ได้ effect กับ user อย่างเราๆ ท่านๆ แต่มีผลมากกับ Core developer ที่คอยดูแล CPython กับ Python Interpreter อยู่ครับ\nด้วยเหตุนี้เองประมาณเดือนสิงหาคมที่ผ่านมาทาง Core Dev หลายๆ คนจึงช่วยๆ กันร่างมาตรฐาน PEP 8001 — Python Governance Voting process ขึ้นมาเป็นอันดับแรกครับ ซึ่งจะพูดถึงวิธีการ vote มาตรฐาน Governance ก่อน โดยจะเปิดให้ Core dev 94 คนเป็นคน vote เพื่อเลือกมาตรฐาน Governance model สำหรับอนาคตต่อไป ในระหว่างนั้นก็ได้มี Core dev หลายๆ คนเสนอมาตรฐานหลายๆ มาตรฐานขึ้นมาหลายๆ ตัวครับ\nจนกระทั่งเดือนธันวาคมระหว่างวันที่ 1–16 จะเป็นช่วงเวลาที่คณะกรรมการการเลือกตั้งเปิดให้โหวตมาตรฐานแต่ละตัวที่มีคนเสนอมา จากที่ติดตามใน twitter นี่บอกได้เลยครับว่า หลายๆ Core dev รอกันจนวันสุดท้ายถึงตัดสินใจ และปิดโหวตในวันที่ 17 ที่ผ่านมานี่เองครับและมาตรฐานที่ได้รับเลือกคือ PEP8016 — The Steering Council Model ครับและเราจะไปดูรายละเอียดของมาตรฐานตัวนี้กันใน blog นี้ครับ\nPEP 8016 — The Steering Council Model หลักการคร่าวๆ ของ PEP8016 คือถึงแม้ Steering council จะมีอำนาจที่กว้างขวางมาก แต่ก็สนับสนุนให้ใช้อำนาจให้น้อยที่สุดเท่าที่จะเป็นไปได้ และแทนที่จะใช้อำนาจนั้นในการตัดสินใจแทน community ให้เลือกที่จะสร้าง process ที่จะกำหนดมาตรฐานต่อๆ ไป นอกจากนั้นแล้วยังส่งเสริมให้แบ่งการตัดสินใจในมาตรฐานเรื่องใหญ่ๆ ให้เป็นเรื่องเล็กๆ ที่จะสามารถตัดสินใจได้แยกจากกันได้\nโดยหัวใจหลักของ The Steering Council Model แบ่งออกเป็น 4 ข้อคือ\n* Be boring\n* Be simple\n* Be comprehensive\n* Be flexible and light-weight\nทีนี้คำถามต่อไปก็คือ ใครจะมาเป็น The Steering council นี้ ใน PEP8016 ระบุไว้ว่า ต้องมี 5 committee ครับ โดยมีหน้าที่ดังนี้ครับ\n* รักษาคุณภาพและความเสถียรของ Python language กับ Python interpreter\n* ส่งเสริมให้การ contribute เข้าถึงได้ง่ายและยั่งยืน\n* รักษาความสัมพันธ์ระหว่าง core team กับ PSF\n* วางมาตรฐานการตัดสินใจของ PEP ในอนาคต\n* หาความเห็นพ้องร่วมกันระหว่าง contributer กับ core team\n* เป็น Court of final appeal ในกรณีที่การตัดสินใจด้วยวิธีอื่นๆ ไม่เวิร์คแล้ว\nจุดที่น่าสนใจอีกจุดหนึ่งที่ผมเห็นในมาตรฐานนี้คือการเลือกตัว Coucil ครับ ซึ่ง ใครสามารถเสนอตัวเองขึ้นมาหรือ core dev เป็นคนเสนอขึ้นมาครับ นอกจากนั้นแล้วพูดถึงเรื่อง Conflict of interest ซึ่งเป็นการป้องกันบริษัทใดๆ nominate การตัดสินใจของ Council ครับโดย สามารถให้สมาชิกของ Council มาจากบริษัทเดียวกันได้มากที่สุด 2 คน ถ้าตอนเลือก council ได้ top 5 แล้ว 3 คนมาจากบริษัทเดียวกันคนที่อยู่อันดับ 3 จากบริษัทเดียวกันจะถูกปัดตกแล้วอันดับ 6 จะถูกเลื่อนขึ้นมาครับ\nตัวมาตรฐาน PEP 8016 ยังไม่หมดแค่นี้นะครับ ยังมีการพูดถึงการให้ออกจาก council ในกรณีต่างๆ รวมถึงบทบาทของ Core team ด้วย ใครสนใจศึกษาเพิ่มเติมไปตามได้ตามลิ้งค์ข้างล่างเลยครับ\nReference https://discuss.python.org/t/python-governance-vote-december-2018-results/546\nhttps://www.python.org/dev/peps/pep-8016/\nOriginal post at: https://medium.com/pythonbycow/pep-8016-and-the-future-of-python-govenance-dabd2362dd42\n","permalink":"https://yothinix-com.pages.dev/pep-8016-and-the-future-of-python-govenance/","summary":"\u003cp\u003eอย่างที่ทุกคนรู้นะครับว่า Guido ได้ถอดตัวออกจากการเป็น BDFL Role ที่เป็นมาอย่างยาวนานในช่วงกลางปีที่ผ่านมา แล้วการออกนั้นถึงแม้จะไม่ได้ effect กับ user อย่างเราๆ ท่านๆ แต่มีผลมากกับ Core developer ที่คอยดูแล CPython กับ Python Interpreter อยู่ครับ\u003c/p\u003e\n\u003cp\u003eด้วยเหตุนี้เองประมาณเดือนสิงหาคมที่ผ่านมาทาง Core Dev หลายๆ คนจึงช่วยๆ กันร่างมาตรฐาน \u003cem\u003ePEP 8001 — Python Governance Voting process\u003c/em\u003e ขึ้นมาเป็นอันดับแรกครับ ซึ่งจะพูดถึงวิธีการ vote มาตรฐาน Governance ก่อน โดยจะเปิดให้ Core dev 94 คนเป็นคน vote เพื่อเลือกมาตรฐาน Governance model สำหรับอนาคตต่อไป ในระหว่างนั้นก็ได้มี Core dev หลายๆ คนเสนอมาตรฐานหลายๆ มาตรฐานขึ้นมาหลายๆ ตัวครับ\u003c/p\u003e\n\u003cp\u003eจนกระทั่งเดือนธันวาคมระหว่างวันที่ 1–16 จะเป็นช่วงเวลาที่คณะกรรมการการเลือกตั้งเปิดให้โหวตมาตรฐานแต่ละตัวที่มีคนเสนอมา จากที่ติดตามใน twitter นี่บอกได้เลยครับว่า หลายๆ Core dev รอกันจนวันสุดท้ายถึงตัดสินใจ และปิดโหวตในวันที่ 17 ที่ผ่านมานี่เองครับและมาตรฐานที่ได้รับเลือกคือ \u003cem\u003ePEP8016 — The Steering Council Model\u003c/em\u003e ครับและเราจะไปดูรายละเอียดของมาตรฐานตัวนี้กันใน blog นี้ครับ\u003c/p\u003e","title":"PEP 8016 and the future of Python govenance"},{"content":"ข่าวประจำสัปดาห์ Dropbox complete migrate to Python 3 เวลานี้คงไม่มีใครไม่รู้จัก Dropbox นะครับ แต่อาจจะมีคนไม่รู้ว่า Dropbox เป็นหนึ่งในบริษัทที่ใช้ Python ใหญ่ที่สุดในโลก เฉพาะโค้ดของตัว Application Dropbox นี่ก็เกิน 1 ล้านบรรทัดแล้วครับ\nแต่ว่าถึงจะใช้ Python ใหญ่ที่สุดในโลกโค้ดของที่นั่นก็ยังเป็น Python 2 อยู่ครับ ซึ่งทาง Dropbox เองก็วางแผน Migrate มาตั้งแต่ปี 2015 แล้ว จนถึงวันนี้ ถ้าใครใช้ Application dropbox เวอร์ชั่นล่าสุด ตัวโค้ดที่รันอยู่ข้างล่างก็มีพื้นฐานจาก Python 3.5 เวอร์ชั่นพิเศษแล้วครับ ซึ่งทางบล็อกนี้อธิบายขั้นตอนการ Roll out ตัวโค้ดจาก Python 2.7 -\u0026gt; Python 3 และปัญหาที่เจอคร่าวๆ ครับ\nนอกจากนั้นแล้ว บล็อกนี้เป็นหนึ่งในซีรีย์บล็อกที่จะตามมาอีกหลายบล็อกจาก Dropbox เกี่ยวกับการ Migrate ไปใช้ Python 3 ก็คอยติดตามกันต่อไปได้ครับ\nHow we rolled out one of the largest Python 3 migrations ever — Dropbox, Max Bélanger\nThe State of Developer Ecosystem Survey in 2018 Poll ประจำปีของทาง Jetbrains นะครับ ในส่วนของ Python ปีนี้การใช้งาน Python3 เกิน 75% ของทั้งหมดแล้วครับ และงานที่ใช้ภาษา Python อันดับหนึ่งเลยคือ Data analysis ตามมาด้วย Web Development และ Machine Learning ตามลำดับ\nในส่วนของ Library ที่ใช้งานมากที่สุดจะเป็นเซ็ต Data Science อยู่อันดับหนึ่งเลยครับ ซึ่งประกอบด้วย NumPy, matplotlib, SciPy และ Panda อันดับต่อมาคือ Django, Flask และ Requests ตามลำดับครับ\nPython in 2018 - The State of Developer Ecosystem by JetBrains Over 1400+ developers share their insights on modern Python programming. Keep up with the most relevant technologies and frameworks in this infographic! — JetBrains\nMore coverage on CPython Core Developer Sprint 2018 ถ้าใครติดตามเขียนงูให้วัวกลัวรายสัปดาห์ ของสัปดาห์ที่แล้วจะเห็นว่าเราพูดถึงเรื่อง Core Developer Sprint เยอะหน่อย ซึ่งสัปดาห์นี้ก็มีบล็อกที่เกี่ยวข้องออกมาถึง 3 บล็อกเลยครับ ถ้าใครสนใจเกี่ยวกับการตัดสินใจเกี่ยวกับอนาคตภาษาหรือเรื่อง Implementation Detail ของภาษาก็น่าติดตามมากเลยครับ\nบล็อกแรกเป็น Part 2 ของคุณ Mariatta นะครับ ตอนนี้เน้นพูดถึง PEP581, Contributor License Agreement และ f-string issues ครับ\nPython Core Sprint 2018: Part Two Read up on Part one first. Here are additional discussions and projects that I got involved with during the sprint. PEP 581 PEP 581 is a PEP I wrote about using GitHub issues instead of Roundup as CPython’s issue tracker. During the sprint, I discussed this topic mainly with Ezio … — mariatta.ca, Mariatta\nบล็อกที่สองเป็นของทาง Python Software Foundation เองครับ จะพูดถึงภาพรวมของ Core Developer Sprint ครับ\nCPython Core Developer Sprint 2018 This September, twenty-nine core committers arrived at Microsoft’s main campus in Redmond, Washington, USA for the now-annual core developer\u0026hellip; — Ewa Jodlowska\nบล็อกสุดท้ายเป็นของคุณ Neil Schemenauer ตัวนี้ค่อนข้างจะลงลึกไปในเรื่อง Implementation Detail ของ CPython ครับว่าจะทำยังไงให้ Python 3.8 จะเร็วขึ้นได้มากกว่าเดิม\nPython Core Developer Sprint 2018\nWhy Emulating CPython C API is so hard บล็อกนี้จะพาเราไปรู้จัก cpyext API ของ PyPy ซึ่งเป็น API ที่เอาไว้ต่อกับ C API ของตัว CPython จริงๆ ครับ จะช่วยให้เราเข้าใจขึ้นว่าทำไม library บางตัวถึงรันช้าขึ้นเมื่ออยู่บน PyPy\nInside cpyext: Why emulating CPython C API is so Hard cpyext is PyPy’s subsystem which provides a compatibility layer to compile and run CPython C extensions inside PyPy. Often people ask \u0026hellip; — official C API\nAPIStar as a cross-framework API Tool ต้องบอกว่า APIStar นี่เปลี่ยนทิศทางโปรเจ็คไปมาหลายครั้งจนผมเองก็เริ่มจำไม่ได้แล้วว่าตกลงมันทำอะไรได้บ้าง พอมาเห็น Tweet นี้จากคุณ Tom Christie ซึ่งเป็นคนสร้าง APIStar ก็ทำให้เราพอจะมองเห็นทิศทางของโปรเจ็คได้บ้างครับว่าจะเป็นไปในทาง API tools ที่ทำหน้าที่สร้าง Documents, validate API Schema, Mock server หรือเป็น API Client เอง\nนอกจากนั้นแล้วยังแยกส่วนของ Server ออกมาเพราะอีกโปรเจ็คนึงของบริษัท Encode นี้คือ Starlette โฟกัสในส่วนของ ASGI Server ได้ดีกว่า APIStar ครับ\nส่วนใครที่กำลังสงสัยว่า อ่าวแล้ว Django REST Framework จะไปในทิศทางไหน ในทวีตยังบอกด้วยครับว่าตัว DRF จะเริ่มย้ายจาก coreapi schema ไปใช้ OpenAPI Schema แทนครับ\nI\u0026#39;m going to be trimming all the server stuff out of API Star, and releasing it instead as a framework-agnositic set of API tools for generating API docs, validating schemas, using as a client library, etc...https://t.co/ZQFf3hDuxg\n\u0026mdash; Tom Christie (@starletdreaming) September 21, 2018 PyCon 2019 Call for Proposals สำหรับงานใหญ่ประจำปีอย่าง PyCon ปีหน้าก็เริ่มรับ Talk Proposal แล้วนะครับ ปีหน้าจัดวันที่ 1–9 พฤษภาคม ใครสนใจรายละเอียดหรือ Guideline ในการส่งสามารถกดดูได้ที่ลิ้งค์ข้างล่างเลยครับ\nSpeak at PyCon | PyCon 2019 in Cleveland, Ohio — PyCon 2019 in Cleveland, Ohio\nหรือถ้าใครอยากดูตัวอย่างของ Talk Proposal คุณ Mariatta ก็ได้ทำ documents ตัว Talk Proposal ที่เค้าเคยส่งไว้ที่นี่ครับ\nTalk Proposals by Mariatta — talk-talk-talk documentation — talk-talk-talk\nAuth0 join #Hacktoberfest 2018 คงไม่ต้องแนะนำกันมากนะครับสำหรับ auth0 ซึ่งเป็น identity provider ที่น่าจะมีคนใช้เยอะระดับนึงเลย ผมลองดูๆ ใน https://github.com/auth0 ก็มี Python repository อยู่บ้างโดยเฉพาะ auth0-python ใครสนใจก็ไปช่วย contribute เอาเสื้อกันได้ครับ\nCelebrate Open-Source Software and Hacktoberfest 2018 with Auth0 Auth0 is to excited join Hacktoberfest 2018, a month-long celebration and supporting of open-source software by Digital Ocean, Github, an\u0026hellip; — Auth0 - Blog, Kim Noel\nPython book 40% of at Manning publishing ทาง Manning ได้ออก special page ให้กับคุณ Naomi Ceder ซึ่งเป็น Chair of PSF นะครับมีหลายเล่มน่าสนใจ ก็ไปจับจองกันได้ตามลิ้งค์ข้างล่างเลยครับ\nNaomi’s Picks | Special deals — Special deals\nHumble book bundle: Learn you some code แพ๊คใหม่ของ Humble book bundle นะครับ มีหนังสือ Python อยู่สองสามเล่มเช่น Automate the boring stuff with Python, Python crash course และ Python Playground ใครสนใจก็ไปกดกันได้ครับ ถือว่าเป็นการช่วยองค์กรการกุศลและยังได้หนังสือดีๆ มาอ่านด้วย\nHumble Book Bundle: Learn You Some Code by No Starch Press Pay what you want for awesome ebooks and support charity! — Humble Bundle\nซอร์ฟแวร์อัพเดท Pytest 3.8.1 สำหรับ Library test ยอดนิยมอย่าง pytest ใน release นี้ออกมาแก้ bug อย่างเดียวเลยครับ แต่บั๊กใหญ่ใน release นี้คือมัน discover test ใน __init__.py แล้วมันระเบิดเพราะว่าไม่มี method len() ครับ นอกจากนั้นยังเพิ่มหน้า Deprecate and Removal ใน Document ด้วยเพื่อช่วยให้คนที่ใช้ Pytest เวอร์ชั่นเก่าๆ อัพเดทง่ายขึ้นครับ\npytest/CHANGELOG.rst at main · pytest-dev/pytest The pytest framework makes it easy to write small tests, yet scales to support complex functional testing - pytest/CHANGELOG.rst at main · pytest-dev/pytest — GitHub, pytest-dev\nBlack 18.9b0 สำหรับ code formatter มาแรงอย่าง Black หลังจากห่างหายการอัพเดทไปนานเวอร์ชั่นนี้ได้เพิ่มความสามารถในการ format ตัวเลขให้มี _ (numerical literal) ที่มีตั้งแต่ Python 3.6 ขึ้นไปได้ และอื่นๆ อีกครับ\nGitHub - psf/black: The uncompromising Python code formatter The uncompromising Python code formatter. Contribute to psf/black development by creating an account on GitHub. — GitHub, psf\nScikit-learn 0.20.0 Release ล่าสุดของ Scikit-learn นี้จะเป็นเวอร์ชั่นสุดท้ายที่รองรับ Python 2.7 และ Python 3.4 ลงไปนะครับ เวอร์ชั่นหน้าจะต้องการ Python 3.5 หรือมากกว่า รายละเอียดเพิ่มเติมเกี่ยวกับฟีเจอร์ใหม่ สามารถติดตามได้ใน Document ข้างล่างครับ\nRelease History Release notes for all scikit-learn releases are linked in this page. Tip: Subscribe to scikit-learn releases on libraries.io to be notified when new versions are released. Version 1.0.2, Version 1\u0026hellip;. — scikit-learn\nDatasette 0.25 สำหรับใครที่ไม่รู้จักนะครับ Datasette ช่วยให้เราสร้าง JSON read only API จาก database sqlite ได้ด้วยคำสั่งเดียว ซึ่งในเวอร์ชั่นนี้ได้แก้คำสั่ง published ให้เลือกได้ว่าเราจะใช้ heroku หรือ now ครับ นอกจากนั้นแล้วยังเปลี่ยนไปใช้ pysqlite3 ในการเชื่อมต่อกับ sqlite ทำให้สามารถใช้กับ sqlite เวอร์ชั่นล่าสุดอย่าง 3.25.0 ได้ด้วยครับ ยังมีฟีเจอร์อื่นๆ ที่เพิ่มขึ้นอีกนอกจากนี้ สามารถอ่านเพิ่มเติมได้ที่ release note ข้างล่างเลยครับ\nChangelog — Datasette documentation\nTwine 1.12.1 ในเวอร์ชั่นใหม่ของ twine ได้เพิ่ม command $ twine check ขึ้นมาครับ ช่วยให้เราสามารถเช็ค README file ว่าตรงกับ format ที่ PyPI อ่านได้รึเปล่าครับ\nMaking a PyPI-friendly README — Python Packaging User Guide — Logo\nLogMe 1.2.1 ผมเพิ่งรู้จัก LogMe เมื่อเร็วๆ นี้เองครับ เป็น Library ที่ช่วยให้เขียน Log ใน Python ได้ง่ายขึ้นเพียงแค่แปะ decorator ใครสนใจก็ไปลองใช้กันได้ครับ\nGitHub - BNMetrics/logme: Python Logging For Humans (Also supports configurable color logging for the terminal!) Python Logging For Humans (Also supports configurable color logging for the terminal!) - GitHub - BNMetrics/logme: Python Logging For Humans (Also supports configurable color logging for the termin\u0026hellip; — GitHub, BNMetrics\nClick 7.0 สำหรับ Library ทำ command line ยอดฮิตอีกตัวนะครับ ในเวอร์ชั่นนี้สามารถทำ native autocomplete ใน zsh ได้แล้ว รวมถึง autocomplete ตัว choice ด้วย นอกจากนี้ยังเพิ่ม DateTime และ FloatRange สำหรับ input type ครับ\nอีกส่วนหนึ่งที่สำคัญใน release นี้คือการย้าย document หลักของโปรเจ็คไปไว้ที่ readthedoc ครับ\nClick 7.0 Released — Pallets\nหมดแล้วครับสำหรับสัปดาห์นี้แล้วพบกันใหม่สัปดาห์หน้าครับ\nOriginal post at: https://medium.com/pythonbycow/เขียนงูให้วัวกลัวรายสัปดาห์-ฉบับที่-2-ebabd95bb532\n","permalink":"https://yothinix-com.pages.dev/python-weekly-2/","summary":"\u003ch2 id=\"ขาวประจำสปดาห\"\u003eข่าวประจำสัปดาห์\u003c/h2\u003e\n\u003ch2 id=\"dropbox-complete-migrate-to-python-3\"\u003eDropbox complete migrate to Python 3\u003c/h2\u003e\n\u003cp\u003eเวลานี้คงไม่มีใครไม่รู้จัก Dropbox นะครับ แต่อาจจะมีคนไม่รู้ว่า Dropbox เป็นหนึ่งในบริษัทที่ใช้ Python ใหญ่ที่สุดในโลก เฉพาะโค้ดของตัว Application Dropbox นี่ก็เกิน 1 ล้านบรรทัดแล้วครับ\u003c/p\u003e\n\u003cp\u003eแต่ว่าถึงจะใช้ Python ใหญ่ที่สุดในโลกโค้ดของที่นั่นก็ยังเป็น Python 2 อยู่ครับ ซึ่งทาง Dropbox เองก็วางแผน Migrate มาตั้งแต่ปี 2015 แล้ว จนถึงวันนี้ ถ้าใครใช้ Application dropbox เวอร์ชั่นล่าสุด ตัวโค้ดที่รันอยู่ข้างล่างก็มีพื้นฐานจาก Python 3.5 เวอร์ชั่นพิเศษแล้วครับ ซึ่งทางบล็อกนี้อธิบายขั้นตอนการ Roll out ตัวโค้ดจาก Python 2.7 -\u0026gt; Python 3 และปัญหาที่เจอคร่าวๆ ครับ\u003c/p\u003e\n\u003cp\u003eนอกจากนั้นแล้ว บล็อกนี้เป็นหนึ่งในซีรีย์บล็อกที่จะตามมาอีกหลายบล็อกจาก Dropbox เกี่ยวกับการ Migrate ไปใช้ Python 3 ก็คอยติดตามกันต่อไปได้ครับ\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://dropbox.tech/application/how-we-rolled-out-one-of-the-largest-python-3-migrations-ever\"\u003eHow we rolled out one of the largest Python 3 migrations ever\u003c/a\u003e\n— Dropbox, Max Bélanger\u003c/p\u003e","title":"เขียนงูให้วัวกลัวรายสัปดาห์ ฉบับที่ 2"},{"content":"ไอเดียนี้เริ่มจากอาทิตย์ที่แล้ว ที่รวบข่าวไว้ในโพสๆ เดียว แล้วก็เกิดไอเดียว่า ทำไมไม่ทำเป็น Newsletter เลยหละ มันเลยเป็นที่มาของโพสนี้และโพสต่อๆ ไปครับ โดย​ “เขียนงูให้วัวกลัว รายสัปดาห์” เราจะโฟกัสเฉพาะข่าวที่เกี่ยวข้องกับ Python Community, Core Language / 3rd Parties Release และอื่นๆ ที่มันเกี่ยวข้องกับ Python programming language ครับ\nPython Core Sprint 2018 Image credit: https://twitter.com/VictorStinner/status/1041219533439217665\nทุกๆ ปี Core Python developers จากทั่วทุกมุมโลกจะมารวมตัวกันโดยนัดหมาย 7 วันเพื่อคุยกันในหลายๆ เรื่อง ปีนี้เป็นครั้งที่ 3 ที่จัดขึ้นครับ\nซึ่งผมก็ไม่รู้ทั้งหมดว่าเค้าคุยอะไรกันบ้าง แต่คุณ Mariatta Wijaya ซึ่งเป็นหนึ่งใน Core developer ได้สรุปไว้คร่าวๆ ครับ สนใจก็ตามไปอ่านได้ที่ลิ้งค์นี้เลย (ยังรอ Part two อยู่ T_T)\nPython Core Sprint 2018: Part One For the past week (September 9-14), I’ve been down in Bellevue, WA for my second Core Python sprint. The sprint is hosted by Microsoft, and funded by The PSF. Thanks Last year, I was only able to stay for the sprint for three days. This year I’m able to stay … — mariatta.ca, Mariatta\nนอกจากนั้นแล้วปีนี้ เรายังมี Core Python Developer เพิ่มขึ้นอีก 2 คน และความเจ๋งยิ่งกว่านั้นคือ เป็นผู้หญิงทั้งคู่เลยครับนั่นทำให้จำนวน Core Python Developer ที่เป็นผู้หญิงนั่นเพิ่มขึ้น 2 เท่าเลยทีเดียว (จาก 2 เป็น 4 คน) ก็ขอแสดงความยินดีกับคุณ Lisa Roasch และ Emily Morehouse-Valcarcel ด้วยครับ\nLisa Roasch and Emily Morehouse-Valcarcel @emilyemorehouse have been promoted as CPython core developers! Welcome on board. We doubled our number of women core devs (2 to 4) 😁 Nice move towards more diversity in Python. pic.twitter.com/gckjfOyYPd\n\u0026mdash; Victor Stinner 🐍 (@VictorStinner) September 14, 2018 Linus Torvalds stepping down temporary ข่าวนี้อาจจะไม่ค่อยเกี่ยวกับ Python เท่าไร แต่ก็นับว่าเป็นเรื่องที่ดีครับที่ Linus ยอมลดราความโหดลงบ้าง ที่น่าสนใจเกี่ยวกับบทความนี้คือ มีการพูดถึงเรื่อง Diversity ใน Python Core developer ด้วยครับ ซึ่งเปิดโลกผมมากเพราะไม่เคยรู้มาก่อนเลยว่า Guido สนับสนุน Diversity ถึงขนาดยอมเป็น Mentor ให้เลย ติดตามอ่านเต็มๆ ได้ในบทความครับ\nAfter Years of Abusive E-mails, the Creator of Linux Steps Aside The celebrated coder Linus Torvalds, known for the operating system he created and his aggressive style of communication, says he is seeking help. — The New Yorker, Condé Nast\n90% of top 1440 PyPI package support Python 3 I pimped py3readiness and worked with @brettsky to add more false positives to caniusepython3. About 90% of the top 1440 #PyPI downloads support #Python 3. https://t.co/mZHQyYsvh7 pic.twitter.com/HOuGWJHq99\n\u0026mdash; Christian Heimes (@ChristianHeimes) September 14, 2018 นับวันก็ยิ่งใกล้ปี 2020 เข้าไปทุกขณะนะครับ ซึ่งเป็นปีที่ Python จะหยุด Support Python2.7 ซึ่งเป็น release สุดท้ายของ Python 2 จาก tweet ล่าสุดของคุณ Christian Heimes นะครับ Software ที่มียอด Download สูงสุด 1440 packages ใน PyPI ในขณะนี้ support Python3 ไปแล้วกว่า 90% และ Top 360 packages นั้น support ถึง 99% แล้วครับ ใครยังไม่อัพเกรดก็ใกล้ถึงเวลาแล้ว อย่าชะล่าใจนะครับ ส่วนใครอยากรู้ว่า Package ไหนรองรับได้สามารถไปดูได้ที่ Python 3 readiness ตามลิ้งข้างล่างเลยครับ\nPython 3 Readiness - Python 3 support table for most popular Python packages — Python 3 support table for most popular Python packages\nPython taking over as a major programming language for Astronomy Python is taking over astronomy, 2018Q3 edition: the curve keeps getting steeper! Updated in collaboration with @_russrussruss and @astrowizicist.\nCC @jakevdp @astrofrog @BeaumontChris pic.twitter.com/thJryG2q2R\n\u0026mdash; Juan Nunez-Iglesias (@jnuneziglesias) September 19, 2018 ผลพวงจากการที่ Python เป็นภาษาที่มีอัตราเติบโตสูงสุดทางฝั่ง Data Science ทางฝั่ง Astronomy นี่ก็ไม่น้อยหน้าเหมือนกัน ซึ่งได้แซง IDL กับ Matlab ไปเป็นที่เรียบร้อยแล้วครับ ถ้าใครอยากรู้ว่าสถิตินี้คำนวนยังไง สามารถไปเล่น Notebook ได้ที่ลิ้งค์นี้เลยครับ\nprogramming-languages-in-astronomy/programming-languages-in-ADS.ipynb at 1df4ec72defaa0b66a22ac2837131ca2850107ba · jni/programming-languages-in-astronomy Analysis of programming language mentions in astronomy papers in ADS - programming-languages-in-astronomy/programming-languages-in-ADS.ipynb at 1df4ec72defaa0b66a22ac2837131ca2850107ba · jni/progra\u0026hellip; — GitHub, jni\nNew Asyncio official documentation 🔥 Big news! 🔥\nasyncio documentation has been rewritten from scratch! Read the new version here: https://t.co/Hoa08x3Y3Z.\nHuge thanks to @WillingCarol, @elprans, and @andrew_svetlov for support, ideas, and reviews!\nThread 👇 pic.twitter.com/5kDxkUboVC\n\u0026mdash; Yury Selivanov (@1st1) September 18, 2018 ถ้าใครได้ลองเขียน Python แบบ Async ในช่วงสองปีที่ผ่านมาน่าจะประสบปัญหาเดียวกับผมว่า Document มันอ่านโคตรยากเลยครับ เหมือนเขียนมาเพื่อให้เราไปช่วย Implement ตัว Library เองยังไงยังงั้น\nซึ่งทางคุณ Yury Selivanov นี่ก็ไม่ได้นิ่งนอนใจนะครับ ในฐานะคนที่ผลักดัน asyncio มาตั้งแต่แรก ได้ประกาศก้องว่าเราเขียนมันใหม่หมดเลย ลบความงงงวยที่เคยเขียนก่อนหน้านั้นทิ้งไปทั้งหมด\nผมเข้าไปอ่านนิดหน่อยแล้วเห็นความแตกต่างอย่างเห็นได้ชัดคือแยกส่วนคือ High level / Low level API ออกจากกันอย่างชัดเจน ทำให้คนที่สนใจจะนำไปใช้ไม่ต้องรู้ Low level อย่าง Event loop หรือ Future object ก็ได้ครับ\nใครสนใจก็เข้าไปอ่านได้ที่ลิ้งค์ข้างล่างเลยครับ\nasyncio — Asynchronous I/O — Python 3.10.2 documentation — Logo\nSneak peak on Requests 3.0 คงไม่ต้องแนะนำกันแล้วใช่มั้ยครับ สำหรับ Library ที่ทุกคนตั้งแต่คนเขียน Script Python เล็กๆ ไปจนถึงทำ Data warehouse ขนาดใหญ่ต้องผ่านมือมาทุกคน ซึ่งหลังจากประกาศขอ Funding ไปเมื่อหลายเดือนก่อน ตอนนี้คุณ Kenneth Reitz ก็เริ่มแง้มๆ แผนของ Requests 3.0 ซึ่งเป็น Version หน้าของ Library ตัวนี้ออกมาให้ชมกัน\nหลักๆ คือ Support Python 3.6+ ซึ่งผมเข้าใจว่าให้รองรับกับ Asynchronous programming ส่วนหนึ่ง และอีกส่วนหนึ่งคือแตก Library low level ออกไปเป็น Library ใหม่ชื่อ requestscore ซึ่งมีไว้เพื่อสถานการณ์ที่ I NEED TO SEND AS MANY REQUESTS AS POSSIBLE AS EFFICIENTLY AS POSSIBLE ตามนั้นเลยครับ\nนอกจาก Requests ทางคุณ Kenneth Reitz กำลังพัฒนา Library ตัวใหม่อยู่นะครับ ซึ่งเค้านิยามว่าเป็น Buildpack แบบHeroku บน Kubernetes ซึ่งผมเข้าใจว่าก็น่าจะเป็นงานหลักของเค้าเพราะทาง DigitalOcean ที่ทำงานปัจจุบันของคุณ Kenneth Reitz ก็เพิ่งเปิดตัว Kubernetes ไปได้ไม่นาน ใครสนใจก็ติดตามได้ที่ลิ้งค์ข้างล่างครับ\nGitHub - kennethreitz-archive/bruce-operator: The BRUCE operator. The BRUCE operator. Contribute to kennethreitz-archive/bruce-operator development by creating an account on GitHub. — GitHub, kennethreitz-archive\nNew MyPy Release สำหรับ Type checker มาตรฐานอุตสาหกรรม Python อย่าง MyPy ก็ยังมีอัพเดทเรื่อยๆ นะครับในอัพเดทนี้รองรับการเช็ค Type ใน Callable Protocol และแก้บั๊กอีกจำนวนหนึ่ง รายละเอียดเพิ่มเติมตามลิ้งค์ข้างล่างเลยครับ\nMypy 0.630 Released We’ve just uploaded mypy 0.630 to the Python Package Index ( PyPI ). Mypy is an optional static type checker for Python. This release inc\u0026hellip; — Ivan\nNew Tox release อันนี้ข่าวล่าวันนี้เลย Tox ออกเวอร์ชั่นใหม่นะครับ 3.4.0 มีฟีเจอร์ใหม่ๆ อย่างเช่น เพิ่ม option commands_pre และ commands_post, รองรับไฟล์ pyproject.toml ซึ่งเป็นมาตรฐานใหม่ของ Python package (PEP 518) และอื่นๆ อีก\nChangelog history — tox 3.4.0 documentation — Logo\nBeta Release for IPython 7.0 หลายๆ คนอาจจะไม่รู้ตัวนะครับว่าตัวเองใช้ IPython อยู่ แต่จริงๆ มันคือ engine เบื้องหลังของ Jupyter Notebook ครับ ซึ่งใน Beta release ล่าสุดได้เพิ่มความสามารถในการรองรับ syntax async / await แล้วครับ\nแต่ความสามารถใหม่นี่ก็ทำให้เกิดบั๊กใน magics ของ IPython อย่าง %%timeit เกิด Syntax Error เมื่อใช้ autoawait ข้างบนนะครับ ซึ่งทางยังรอคนแก้บั๊กใครสนใจก็ไปช่วยแก้กันได้ครับ\nAsynchronous in REPL: Autoawait — IPython 8.1.0.dev documentation\nMicrosoft joining Hacktoberfest 2018 ยิ่งใกล้เดือนตุลาคม เราก็ยิ่งเตรียมใจและ Text Editor คู่ใจเพื่อเตรียมรับกับเทศกาล Hacktoberfest ประจำปีนะครับ ซึ่งปีนี้ Microsoft ได้มาร่วมด้วย ซึ่งตามธรรมเนียมครับ Microsoft แจกเสื้อ Limited Edition ด้วย ใครสนใจก็เตรียมตัวให้ดีนะครับ\nWe’re joining Hacktoberfest 2018 - Microsoft Open Source Blog As part of Hacktoberfest, we’ll recognize anyone who submits an October pull request to a Microsoft open source project with a limited-edition t-shirt. — Microsoft Open Source Blog, Bernd Verst\nผมไล่ๆ ดูใน Opensource projects ของ Microsoft นี่มีหลายตัวที่น่าสนใจเลยทีเดียว แต่ที่น่าสนใจสุดคงไม่พ้น Python Extension for VSCode นะครับ สำหรับใครที่สนใจ Contribute ให้ Microsoft ในส่วนของ Python สามารถไล่ดู Project ได้ตามลิ้งข้างล่างเลยครับ\nMicrosoft Open Source Microsoft Open Source: get involved in open source communities, discover projects and ecosystems Microsoft is involved in, and learn about the Microsoft open source program — Microsoft Open Source\nปล.จริงๆ วันอังคารที่ผ่านมาเป็นกำหนด Python 3.7.1 final release นะครับ แต่มีปัญหานิดหน่อยกับ implementation ของ C locale coercion (PEP 538) ในนาทีสุดท้ายเลยต้องเลื่อน release ออกไปซึ่งคาดว่าน่าจะเป็นวันที่ 28 กันยายนนี้ ก็คอยติดตามกันครับ\nOriginal post at: https://medium.com/pythonbycow/เขียนงูให้วัวกลัวรายสัปดาห์-ฉบับที่-1-2423a65e8a02\n","permalink":"https://yothinix-com.pages.dev/python-news-weekly-1/","summary":"\u003cp\u003eไอเดียนี้เริ่มจากอาทิตย์ที่แล้ว ที่รวบข่าวไว้ในโพสๆ เดียว แล้วก็เกิดไอเดียว่า ทำไมไม่ทำเป็น Newsletter เลยหละ มันเลยเป็นที่มาของโพสนี้และโพสต่อๆ ไปครับ โดย​ \u003cem\u003e“เขียนงูให้วัวกลัว รายสัปดาห์”\u003c/em\u003e เราจะโฟกัสเฉพาะข่าวที่เกี่ยวข้องกับ Python Community, Core Language / 3rd Parties Release และอื่นๆ ที่มันเกี่ยวข้องกับ Python programming language ครับ\u003c/p\u003e\n\u003ch1 id=\"python-core-sprint-2018\"\u003ePython Core Sprint 2018\u003c/h1\u003e\n\u003cp\u003e\u003cimg src=\"/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp\"\n       srcset=\"/python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_aaef0f626711cec8.webp 480w, /python-news-weekly-1/1-B_8HrIjnpdeiPJK2p8YOEg_hu_71f7be265dc53592.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"642\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eImage credit: \u003ca href=\"https://twitter.com/VictorStinner/status/1041219533439217665\"\u003ehttps://twitter.com/VictorStinner/status/1041219533439217665\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eทุกๆ ปี Core Python developers จากทั่วทุกมุมโลกจะมารวมตัวกันโดยนัดหมาย 7 วันเพื่อคุยกันในหลายๆ เรื่อง ปีนี้เป็นครั้งที่ 3 ที่จัดขึ้นครับ\u003c/p\u003e\n\u003cp\u003eซึ่งผมก็ไม่รู้ทั้งหมดว่าเค้าคุยอะไรกันบ้าง แต่คุณ Mariatta Wijaya ซึ่งเป็นหนึ่งใน Core developer ได้สรุปไว้คร่าวๆ ครับ สนใจก็ตามไปอ่านได้ที่ลิ้งค์นี้เลย (ยังรอ Part two อยู่ T_T)\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://mariatta.ca/core-sprint-2018-part-1.html\"\u003ePython Core Sprint 2018: Part One\u003c/a\u003e\nFor the past week (September 9-14), I’ve been down in Bellevue, WA for my second Core Python sprint. The sprint is hosted by Microsoft, and funded by The PSF. Thanks Last year, I was only able to stay for the sprint for three days. This year I’m able to stay …\n— mariatta.ca, Mariatta\u003c/p\u003e","title":"เขียนงูให้วัวกลัวรายสัปดาห์ ฉบับที่ 1"},{"content":"ถ้าจะมีงานหนึ่งที่ผมทำแล้วรู้สึกสนุกและท้าทายทุกครั้งที่อยู่ที่ Pronto Tools ก็คือการอัพเกรดเวอร์ชั่น Python นี่แหละครับ ตอนผมเข้ามาทำงานใหม่ๆ ทีมใช้ Python 3.5 อยู่ปีที่แล้วเลยอัพเกรดเป็น 3.6 และในปีนี้เนื่องในโอกาส Python 3.7 ออก เราก็รอแปปนึงจนคิดว่าอะไรๆ พร้อมแล้ว ถึงจะอัพเกรด\nทำไมถึงต้องอัพเกรด เพราะเราอยากใช้ของใหม่ๆ ครับ อันนี้เหตุผลสั้นๆ เลย เราอยากใช้ breakpoint() ตัวใหม่ เราอยากใช้ dataclasses เราอยากใช้ from __future__ import annotations และอื่นๆ อีกมากมาย นี่ยังไม่รวมถึง Library ต่างๆ ที่เกี่ยวข้องที่บาง Library ทำมาเพื่อ Python 3.7+ แล้ว ถึงแม้ว่า Python 3.6 กว่าจะ end of life ก็ตั้งปี 2021 แต่รีบๆ อัพเกรดไว้ก็ไม่เสียหายครับ\nข้อดีอีกอย่างของการอัพเกรดในช่วงนี้คือ หา Issues ง่ายครับหลายๆ Library ที่เราพึ่งพาอยู่ในโปรเจ็คเราก็ยังมีอีกหลายคนที่ต้องการอัพเกรดเหมือนกัน แต่ถ้าหาไม่เจอ นี่ก็เป็นโอกาสอันดีครับที่จะได้ไป Contribute ให้ Library หลายๆ ตัวให้รองรับ Python 3.7 ในตัว\nHow to upgrade แบบไม่เจ็บตัว อย่างแรกเลยครับ ถ้าอยากอุ่นใจ codebase เราควรจะมี Unit test ครับ ซึ่งสิ่งหนึ่งที่ผมเรียนรู้จากช่วงอัพเกรดที่ผ่านมาคือ codebase ของ SimpleSat ที่เราดูแลอยู่บาง service มี coverage อยู่ที่ประมาณ 97% files, 98% lines covered เลยครับ ส่วนตัวผมเองเลยค่อนข้างอุ่นใจไประดับนึงละ\nเนื่องจากว่า environment เราอยู่บน Docker 100% โนะ วิธีอัพเกรดคือแค่เปลี่ยน base image จาก Python 3.6 เป็น Python 3.7 แล้วก็ลอง Build images ของทุก microservice service ใหม่ดู จากนั้นก็รัน docker-compose stack ใน local แล้วดูว่าเกิดอะไรขึ้น ข้างล่างนี่คือ List ของปัญหาที่เราเจอกับ Library ที่เราใช้อยู่ครับ\nuWSGI เมื่อประมาณ 2 เดือนที่แล้วเราก็เพิ่งอัพเกรด uWSGI เป็นเวอร์ชั่น 2.0.17 พอมาถึงวันที่เราเปลี่ยนมาใช้ Python 3.7 ระเบิดครับ เหตุผลเพราะว่า C-API PyOS_AfterFork มันดัน Deprecate ใน Python 3.7 ครับ โชคดีที่ Issue นี้มีคนแก้ไว้แล้วและ uWSGI ได้ออก release 2.0.17.1 มาแก้ปัญหานี้แล้วเรียบร้อยครับ\nPython 3.7.0: PyOS_AfterFork is deprecated · Issue #1813 · unbit/uwsgi Since Python 3.7.0 the PyOS_AfterFork is deprecated. uwsgi is using this function in python_plugin.c. — GitHub, unbit\nPyToolz สำหรับคนที่ไม่รู้จักนะครับ PyToolz เป็น Library functional programming ที่ได้รับความนิยมมากตัวหนึ่งใน Python และเราใช้มันในหลายๆ ส่วนของ codebase เราครับ เวอร์ชั่นที่เราใช้อยู่คือ 0.8.2 พออัพเกรดมาใช้ Python 3.7 สิ่งที่เราเจอคือ\nSyntaxError: Generator expression must be parenthesized\nซึ่งโค้ดบางส่วนใน Library ยังเขียน Generator expression แบบไม่มีวงเล็บอยู่นั่นเองครับ ซึ่งเป็น Change in behavior หนึ่งใน Python 3.7 นะครับ\nPython 3.7 now correctly raises a SyntaxError, as a generator expression always needs to be directly inside a set of parentheses and cannot have a comma on either side, and the duplication of the parentheses can be omitted only on calls. (Contributed by Serhiy Storchaka in bpo-32012and bpo-32023.)\nแต่ก็โชคดีเหมือนกันครับที่ Library ออก patch มาแก้ไขเรื่องนี้แล้วเพียงแค่อัพไป release 0.9.0 ก็ไม่มีปัญหานี้แล้วครับ\npython 3.7 compatibility bug · Issue #404 · pytoolz/toolz In the conda\u0026rsquo;s vendored version of toolz, when testing against python 3.7, I got this error Traceback (most recent call last): File \u0026ldquo;/opt/conda-py37/lib/python3.7/site-packages/conda/excep\u0026hellip; — GitHub, pytoolz\nDjango เนื่องจากสถาปัตยกรรมของเราเป็น Microservice โนะแล้ว แต่ละ service ก็เกิดก่อนหลังไม่พร้อมกันเลยมีบางตัวที่ใช้ Django ไม่ตรงกับตัวอื่น ปัญหานี้เจอใน Django 1.11.x ครับและเป็นปัญหาเดียวกับ PyToolz เลยคือ Generator expression must be parenthesized ซึ่งก็มีคนเปิด issue ไว้แล้วทีนี่\nRefs #28814 \u0026ndash; Fixed “SyntaxError: Generator expression must be paren… · django/django@931c60c …thesized” on Python 3.7. Due to https://bugs.python.org/issue32012. — GitHub, django\nแต่ตัวนี้โชคร้ายหน่อยตรงที่ Maintainer ของ Django ไม่อัพเดทให้กับ 1.11 แล้วเนื่องจากหมด Mainstream support ไปแล้วครับ\nPer the FAQ, Django 1.11.x is not compatible with Python 3.7.\nDjango 1.11.x reached end of mainstream support on December 2, 2017 and it receives only data loss and security fixes until its end of life.\nเพราะฉะนั้นในเคสนี้ เราเลยเหลือทางเลือกทางเดียวคือ อัพเกรด Django เลยครับจาก 1.11 กระโดดไปเป็น 2.1 ซึ่งเป็นเวอร์ชั่นล่าสุดเลย แต่เนื่องจากเราอัพเกรด Django เพราะฉะนั้น Library ที่เราใช้ที่เกี่ยวข้องกับ Django อย่างเช่น Django REST Framework, django-filter, etc. ก็เลยต้องอัพตามไปด้วย แต่โดยรวมแล้วก็ไม่มีปัญหาอะไรครับ นอกจากต้องเพิ่มอาร์กิวเม้นต์ on_delete เข้าไปใน ForeignKey ของ Django ด้วย\nFreezegun Freezegun ก็เป็น Library ตัวนึงที่เราใช้งานสูงมากครับ ช่วยให้เราเขียน Unit test ที่มีเวลาเข้ามาเกี่ยวข้องได้ง่ายขึ้นมาก เวอร์ชั่นที่เราใช้อยู่ปัจจุบันคือ 0.3.9 ครับ ซึ่งพออัพเกรดมาใช้ Python 3.7 ก็เจอปัญหาเลยว่า\nAttributeError: module \u0026lsquo;uuid\u0026rsquo; has no attribute \u0026lsquo;_uuid_generate_time\u0026rsquo;\nเคสนี้ก็ยังโชคดีอยู่ครับที่ตัว Library ออก patch มาแก้ไขเรียบร้อยแล้วเพียงแค่อัพเกรดเป็น 0.3.10 ก็ไม่เจอปัญหานี้แล้วครับ แต่เคสนี้เป็นเคสที่แปลกมากอย่างนึงคือ ผมพยายามหาใน Changelog ของ Python 3.7 แต่ไม่มีที่ไหนพูดถึง Remove attribute _uuid_generate_time เลยครับ\nAttributeError: module ‘uuid’ has no attribute ‘_uuid_generate_time’ on Python 3.7.0b1 · Issue #225 · spulec/freezegun The upcoming Python 3.7 version drops the internal _uuid_generate_time function in the uuid module, which makes freezegun fail on import: Python 3.7.0b1+ (heads/3.7:7f38637853, Feb 1 2018, 13:09:53\u0026hellip; — GitHub, spulec\nDropbox ในเคสของ Dropbox SDK ปัญหาค่อนข้างจะตรงไปตรงมาครับคือ ใน codebase ของตัว Library ยังมีตัวแปรบางตัวใช้คำว่า async ซึ่งใน Python 3.7 กลายมาเป็น Reserved keywords แล้ว อันนี้ก็อัพเดทไปใช้เวอร์ชั่นล่าสุด 9.0.0 ก็ไม่มีปัญหานี้แล้วครับ\nFailure to import on Python 3.7.0b4 · Issue #145 · dropbox/dropbox-sdk-python async is now a keyword leading to: import: \u0026lsquo;dropbox\u0026rsquo; Traceback (most recent call last): File \u0026ldquo;/opt/conda/conda-bld/dropbox_1525570948590/test_tmp/run_test.py\u0026rdquo;, line 2, in \u0026lt;modu\u0026hellip; — GitHub, dropbox\nFlake8 พอเราเปลี่ยนมาใช้ Python 3.7 ตัว Flake8 จากที่รันเงียบๆ อยู่ดีๆ ก็มี Warning เพิ่มขึ้นมาว่า\nFutureWarning: Possible nested set at position 1\nEXTRANEOUS_WHITESPACE_REGEX = re.compile(r\u0026rsquo;[[({] | []}),;:]\u0026rsquo;)\nซึ่งก็มีคนไปเปิด issues ไว้แล้วครับที่ Pycodestyle (ตัว Flake8 ขี่อยู่บน Library อีกสามตัวหนึ่งในนั้นคือ Pycodestyle ระหว่างนี้เราก็ได้แต่รอ Flake8 ออกเวอร์ชั่นใหม่ ก็ทนรำคาญไปอีกนิดหน่อย แต่โดยรวมแล้วก็ยังทำงานได้ปกติครับ\nFutureWarning: Possible nested set for EXTRANEOUS_WHITESPACE_REGEX · Issue #728 · PyCQA/pycodestyle When running pycodestyle 2.3.1 with Python 3.7, I get: /home/florian/proj/qutebrowser/git/.tox/flake8/lib/python3.7/site-packages/pycodestyle.py:113: FutureWarning: Possible nested set at position \u0026hellip; — GitHub, PyCQA\nCelery ตัว Celery นี่เป็นเคสที่ปวดหัวที่สุดละครับ คือตัว Package หลักที่อยู่ใน PyPI ยังไม่ support Python 3.7 จนมีคนไปโวยวายเยอะมาก ว่าทำไมไม่ support ฟะ ก็น่าจะมีคนใช้เยอะนิ ซึ่งจริงๆ ใน Master branch ของตัว Library เองก็มีคนแก้ปัญหา compatibility กับ Python 3.7 แล้วนะครับ ปัญหาเล็กมากแค่เรื่อง async keywords เหมือนเคส Dropbox เลย แต่ทาง Maintainer ของ Celery ก็ไม่ยอมออก Release เล็กๆ ออกมาแก้เรื่องนี้ (คงจะรอจน release 4.3 ออกอย่างไวสุดก็เดือนหน้า) ครับ\nSupport `async` keyword in python 3.7 · Issue #4500 · celery/celery Checklist I have included the output of celery -A proj report in the issue. (if you are not able to do this, then at least specify the Celery version affected). I have verified that the issue exist\u0026hellip; — GitHub, celery\nระหว่างนี้ ถ้าอยากใช้ Celery กับ Python 3.7 ก็แนะนำให้ pip จาก GitHub ที่ commit นี้ไปก่อนนะครับจนกว่า Celery 4.3.x จะออก\npip install git+https://github.com/celery/celery.git@ced86ea58859e9f704cc781c59ea3e137b199638\nส่วนถ้าใครอยากอ่านดราม่าใน Celery ก็ติดตามได้ที่ issues นี้เลยครับ\nCelery release cycle · Issue #4957 · celery/celery There is no reasonable release cycle for Celery. If something is broken, it could be broken in stable version for a very long time, even if it\u0026rsquo;s actually fixed at master. Steps to reproduce Fix\u0026hellip; — GitHub, celery\nหลังจากอัพเกรดจนทุก Library ใช้งานได้ปกติแล้ว Unit test ผ่านหมด เราก็ยังไม่ไว้ใจ 100% ครับ วันต่อมาหลังจากเรา Deploy ตัว Docker image ใหม่ที่อัพเกรดแล้วไปเครื่อง development เราทำ Manual testing ทุกฟีเจอร์ที่เกี่ยวข้องกับแอพเลย ซึ่งโชคดีที่ไม่เจอปัญหาอะไรที่ร้ายแรง หรือเกี่ยวข้องโดยตรงจากการอัพเดทครับ เราเลยอัพเกรดขึ้น Production ในบ่ายวันนั้นเลย ซึ่งก็ยังไม่เจอปัญหาอะไรมาจนถึงปัจจุบัน\nUpgrade แล้วได้อะไรบ้าง อันนี้เป็นสิ่งที่ผมนึกได้สุดท้ายก่อนที่เราจะกดอัพเกรดเครื่อง Development ครับคือพยายามเก็บ Resource ทุกอย่างว่าก่อนและหลัง Deploy เปลี่ยนไปมากแค่ไหนและข้างล่างนี่คือ สิ่งที่เกิดขึ้นครับ\nจะเห็นว่า Memory Usage ลดลงอย่างเห็นได้ชัดมากๆ เกือบ 3 GB เลยทีเดียว ถึงแม้วันต่อมามันจะพุ่งมาเฉลี่ยอยู่ที่ ~5GB แต่ก็ไม่ขึ้นไปแตะ 6.75GB เหมือนก่อนอัพเกรดเลยครับ นอกจากนั้นแล้วตอนที่ดู Monitor ใน Datadog สิ่งที่เห็นอีกอย่างนึงคือ Load Average โดยรวมต่อ container ลดลงอย่างเห็นได้ชัดครับ ซึ่งค่อนข้างจะสอดคล้องกับผลที่ได้จาก Benchmark ใน Blog ข้างล่างนี้ครับ\nWhich is the fastest version of Python? | HackerNoon Of course, “it depends”, but what does it depend on and how can you assess which is the fastest version of Python for your application? Is Python 3 slower than Python 2? Which version of Python 3 is the fastest and what other options do you have for speed? Using the performance suite utility The cor… — Hackernoon logo, Anthony Shaw\nสรุป การอัพเกรดมีความเสี่ยงนะครับ โปรดใช้ความระมัดระวังในการอัพเกรด แต่ความคุ้มค่าที่ได้มาก็คุ้มที่จะเหนื่อยอยู่ครับทั้งฟีเจอร์ใหม่ๆ ของภาษาและ Library ที่เกี่ยวข้อง\nอีกอย่างที่สำคัญและอยากจะฝากไว้คือ Unit Test ครับ เราเขียน Unit Test ไม่ใช่แค่ให้มันผ่านๆ ไป แต่หัวใจของมันคือทำให้เรามั่นใจว่า ตัว Unit ของ Software เราจะยังทำงานเหมือนเดิม ถ้าเราทำการเปลี่ยนแปลงอะไรๆ ใน codebase ครับ\nก็ขอบคุณทุกคนที่อ่านมาจนถึงบรรทัดนี้ครับ หวังว่าจะเป็นประโยชน์แล้วก็ช่วยให้คนที่กำลังลังเลจะใช้ Python 3.7 สบายใจขึ้น แล้วพบกันใหม่ Entry หน้าสวัสดีครับ\nOriginal post at: https://yothinix.medium.com/share-ประสบการณ์-upgrade-python-3-7-3f27300d966d\n","permalink":"https://yothinix-com.pages.dev/upgrade-python-3-7/","summary":"\u003cp\u003eถ้าจะมีงานหนึ่งที่ผมทำแล้วรู้สึกสนุกและท้าทายทุกครั้งที่อยู่ที่ Pronto Tools ก็คือการอัพเกรดเวอร์ชั่น Python นี่แหละครับ ตอนผมเข้ามาทำงานใหม่ๆ ทีมใช้ Python 3.5 อยู่ปีที่แล้วเลยอัพเกรดเป็น 3.6 และในปีนี้เนื่องในโอกาส Python 3.7 ออก เราก็รอแปปนึงจนคิดว่าอะไรๆ พร้อมแล้ว ถึงจะอัพเกรด\u003c/p\u003e\n\u003ch1 id=\"ทำไมถงตองอพเกรด\"\u003eทำไมถึงต้องอัพเกรด\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003eเพราะเราอยากใช้ของใหม่ๆ ครับ\u003c/strong\u003e อันนี้เหตุผลสั้นๆ เลย เราอยากใช้ \u003cstrong\u003ebreakpoint()\u003c/strong\u003e ตัวใหม่ เราอยากใช้ \u003cstrong\u003edataclasses\u003c/strong\u003e เราอยากใช้ \u003ccode\u003efrom __future__ import annotations\u003c/code\u003e และอื่นๆ อีกมากมาย นี่ยังไม่รวมถึง Library ต่างๆ ที่เกี่ยวข้องที่บาง Library ทำมาเพื่อ Python 3.7+ แล้ว ถึงแม้ว่า Python 3.6 กว่าจะ \u003cem\u003eend of life\u003c/em\u003e ก็ตั้งปี 2021 แต่รีบๆ อัพเกรดไว้ก็ไม่เสียหายครับ\u003c/p\u003e\n\u003cp\u003eข้อดีอีกอย่างของการอัพเกรดในช่วงนี้คือ หา Issues ง่ายครับหลายๆ Library ที่เราพึ่งพาอยู่ในโปรเจ็คเราก็ยังมีอีกหลายคนที่ต้องการอัพเกรดเหมือนกัน แต่ถ้าหาไม่เจอ นี่ก็เป็นโอกาสอันดีครับที่จะได้ไป Contribute ให้ Library หลายๆ ตัวให้รองรับ Python 3.7 ในตัว\u003c/p\u003e","title":"Share ประสบการณ์ Upgrade Python 3.7"},{"content":"#pythontricks วันนี้ครับ พอดีวันนี้มีปัญหากับ API แล้วต้องทำ Load test แบบง่ายๆ เร็วๆ เลยไปเจอ locustio มาครับ และมันง่ายมากเลย\nLocust เป็น Load testing tool ตัวนึงครับ ผมไม่เคยใช้ตัวอื่นแต่พอมาใช้ตัวนี้ วันนี้ เช้านี้ บอกได้เลยว่ามันใช้ง่ายมากครับ เพียงแค่เราสร้าง TaskSet ขึ้นมา โดย TaskSet เนี่ยจะเป็นคล้ายๆ Test Case ว่าเราจะทำอะไรกับ Server บ้าง ในเคสนี้ก็คือยิง HTTP Request ครับ ลักษณะการเขียนจะคล้ายๆ กับพวกเทสของ Django หรือ DRF เลยคือเป็น self.client.\u0026lt;method\u0026gt;\nพอเราเขียน TaskSet เสร็จแล้วเราก็ต้องสร้างอีก Class นึงครับเป็น Locust class ซึ่ง Class นี้จะเป็นตัวแทนของ User ที่ใช้ TaskSet อีกทีนึง ซึ่งเราสามารถกำหนด min_wait และ max_wait ได้ซึ่งจะเป็นค่าที่ตัว Locust ใช้สุ่มในการ Generate Task ขึ้นมาครับ พอเราเขียนเสร็จแล้วหน้าตาของ locustfile.py ก็จะประมาณนี้\nพอเราได้ Locustfile แล้วทีนี้เราก็ต้องสั่งรันครับ ซึ่งง่ายมากเพียงแค่สั่ง\nlocust -f locustfile.py - -host=\u0026lt;hostname\u0026gt;\nแล้วตัว Locust จะรัน Server ขึ้นมาครับ เราสามารถเข้าไปได้ที่ localhost:8089 โดยมันจะให้เราใส่จำนวน Concurrent user ที่เราต้องการจะยิง แล้วก็อัตราการ Spawn user ขึ้นมาว่ากี่ user / วินาที ครับพอใส่ข้อมูลเรียบร้อยมันก็จะยิงทันทีเลยครับหน้าตาของตัว Server ก็จะประมาณนี้\nหน้าสรุป Request ทั้งหมดที่ยิง\nมี Chart ให้ดูอัตราการโหลดด้วย\nก็สั้นๆ ประมาณนี้ครับ เพิ่งลองได้ไม่ถึงวันเลยเล่าได้แค่นี้ แต่ก็นับว่าเป็นเครื่องมือที่ยิงได้โหดพอสมควรเลยทีเดียว ทำเอา CPU ผมวิ่งจี๋เลย ถ้าอยากศึกษาเพิ่มเติมแนะนำที่เว็บของตัว Library เลยครับตามที่อยู่ข้างล่าง แล้วพบกันใหม่ Post หน้าครับ\nLocust.io An open source load testing tool. Define user behaviour with Python code, and swarm your system with millions of simultaneous users. — Locust, Jonatan Heyman\nOriginal post at: https://medium.com/pythonbycow/สร้าง-load-test-ง่ายๆ-ด้วย-locust-2d3123f2e8d2\n","permalink":"https://yothinix-com.pages.dev/python-load-test-with-locust/","summary":"\u003cp\u003e#pythontricks วันนี้ครับ พอดีวันนี้มีปัญหากับ API แล้วต้องทำ Load test แบบง่ายๆ เร็วๆ เลยไปเจอ \u003ca href=\"https://locust.io/\"\u003elocustio\u003c/a\u003e มาครับ และมันง่ายมากเลย\u003cbr\u003e\n\u003cbr\u003e\n\u003cstrong\u003eLocust\u003c/strong\u003e เป็น Load testing tool ตัวนึงครับ ผมไม่เคยใช้ตัวอื่นแต่พอมาใช้ตัวนี้ วันนี้ เช้านี้ บอกได้เลยว่ามันใช้ง่ายมากครับ เพียงแค่เราสร้าง \u003cstrong\u003eTaskSet\u003c/strong\u003e ขึ้นมา โดย TaskSet เนี่ยจะเป็นคล้ายๆ Test Case ว่าเราจะทำอะไรกับ Server บ้าง ในเคสนี้ก็คือยิง HTTP Request ครับ ลักษณะการเขียนจะคล้ายๆ กับพวกเทสของ Django หรือ DRF เลยคือเป็น self.client.\u0026lt;method\u0026gt;\u003cbr\u003e\n\u003cbr\u003e\nพอเราเขียน TaskSet เสร็จแล้วเราก็ต้องสร้างอีก Class นึงครับเป็น \u003cstrong\u003eLocust class\u003c/strong\u003e ซึ่ง Class นี้จะเป็นตัวแทนของ User ที่ใช้ TaskSet อีกทีนึง ซึ่งเราสามารถกำหนด min_wait และ max_wait ได้ซึ่งจะเป็นค่าที่ตัว Locust ใช้สุ่มในการ Generate Task ขึ้นมาครับ พอเราเขียนเสร็จแล้วหน้าตาของ locustfile.py ก็จะประมาณนี้\u003c/p\u003e","title":"สร้าง Load Test ง่ายๆ ด้วย Locust"},{"content":"สิ่งหนึ่งที่เราจะเจอหลังจากเขียน Unit Test มาได้ซักพักคือ มันจะมีบางอย่างที่เราควบคุมมันไม่ได้ครับ บางอย่างนั้นอาจจะเป็นไปได้ตั้งแต่ ค่าสุ่ม, เวลา, การอ่านเขียนไฟล์,​ การแก้ไข Database อะไรอย่างนี้เป็นต้น\nพอเรามาเจออะไรพวกนี้ มันจะเกิดคำถามขึ้นมาทันทีว่า แล้วเราจะเทสมันยังไง ถ้ามันเปลี่ยนตลอดเวลา คำตอบของคำถามนั้นก็คือ เราต้อง Mock มันครับ ซึ่ง Python มี standard library ไว้จัดการเรื่องนี้ครับคือ unittest.mock.patch\nPatch นั้นมีหลายท่า ก่อนหน้านี้ผมเคยเล่าให้ฟังบางส่วนแล้วว่าเราจะจัดการกับการ Patch หลายๆ module ยังไง ซึ่งใช้ ExitStack() มาช่วยในการจัดการ context สนใจไปอ่านต่อได้ที่นี่ครับ\nPython - ExitStack แบบสั้นๆ วันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager — Yothinix, Yothin Muangsommuk\nแต่จริงๆ เราสามารถใช้ patch ได้ถึง 3 แบบเลย แล้วแต่สถานการณ์ครับ\npatch decorator แบบแรกคือ ใช้เป็น decorator ครับแบบนี้จะเหมาะกับ การที่เรา patch ฟังก์ชั่นจำนวนน้อยๆ ซึ่งพอมันน้อยเนี่ยมันจะยังไม่รบกวน test function signature มาก ทำให้เรา ยังพออ่านได้อยู่ว่า Test Case นั้นชื่ออะไร\npatch context แบบที่สอง น่าจะเคยเห็นมาจาก Tricks ข้างบนแล้วนะครับ คือเราใช้ภายใต้ context manager แทน แบบนี้ทำให้เราไม่ต้องมี decorator มากวนใจตรง function signature แล้วครับ ตัว patch จะถูกใช้ใน test function เลย แต่ข้อเสียคือ เราก็จะเสีย indent ไปนิดหน่อยตอนเราสั่งรัน function ที่เราจะเทส\npatch manually แบบสุดท้าย คือเราจะสั่ง patch เองครับผ่าน method start() และหยุด patch ผ่าน stop() พอเราสั่ง patch แบบนี้แล้ว มันเปิดโอกาสให้เราทำอะไรได้หลายๆ อย่างมากเช่น เรา patch ไว้ตั้งแต่ setUp เลย ถ้าฟังก์ชั่นนี้ต้อง patch ทุก TestCase ซึ่งจะช่วยลด Duplication ของ patch ใน code ไปได้ หรือเราอยากให้ TestCase เรามี indent น้อยๆ ก็จะช่วยได้เหมือนกัน\nแต่พลังที่ยิ่งใหญ่มาพร้อมกับความรับผิดชอบที่ใหญ่ยิ่งครับ วิธีนี้สำคัญสุดเลยคือ ต้องอย่าลืมหยุด patch ครับ จะสังเกตุว่า ตอนเราใช้ decorator หรือ context manager เราไม่เคยต้องกังวลเรื่องนี้เลย เป็นเพราะว่าพอเราใช้สองอย่างนั้น พอออกจาก context มันจะหยุด path ให้เราอัตโนมัติครับ\nขอสรุปสั้นๆ อีกทีละกันว่าเราควรควรใช้ Patch ท่าไหนตอนไหน\npatch decorator ใช้เวลาที่เรา patch แค่หนึ่งฟังก์ชั่น patch as context manager ใช้เวลาที่เราจะ patch หลายๆ ฟังก์ชั่น patch manually start / stop ใช้เวลาต้อง patch เหมือนๆ กันทุกฟังก์ชั่นใน Test Suite หรือลดความซ้ำซ้อนของโค้ด เป็นยังไงกันบ้างครับ การจะ Mock นี่ไม่ใช่เรื่องเล็กๆ เลย ข้อเสียของ patch ของ Python อีกอย่างนึงคือ Official Document อ่านยากมากครับ กว่าจะเข้าใจวิธีใช้ ต้องบอกว่าเทคนิคนี้ผมก็อ่านๆ มาจากหลายๆ Blog เหมือนกันครับ ใครสนใจศึกษาเพิ่มเติมก็ลองดูได้ตามลิ้งข้างล่างเลยครับ\nReference Python Mock Cookbook The python mock library is one of the awesome things about working in Python. No matter what code you’re unit testing, it’s possible to mock out various pieces with very little test code. That being said, it’s sometimes difficult to figure out the exact syntax for your situation. I attribute this to… — Chase Seibert Blog, Chase Seibert\nTest — pysheeet — Logo\nThe many flavors of mock.patch I write a lot of unit tests. Unfortunately, my code often requires monkey patching to be properly unit tested. I frequently use the patch function … — Trey Hunner, Trey Hunner\nOriginal post at: https://medium.com/pythonbycow/patch-ยังไงให้อ่านรู้เรื่อง-8d504b01b1ec\n","permalink":"https://yothinix-com.pages.dev/readable-python-patching/","summary":"\u003cp\u003eสิ่งหนึ่งที่เราจะเจอหลังจากเขียน Unit Test มาได้ซักพักคือ มันจะมีบางอย่างที่เราควบคุมมันไม่ได้ครับ บางอย่างนั้นอาจจะเป็นไปได้ตั้งแต่ ค่าสุ่ม, เวลา, การอ่านเขียนไฟล์,​ การแก้ไข Database อะไรอย่างนี้เป็นต้น\u003c/p\u003e\n\u003cp\u003eพอเรามาเจออะไรพวกนี้ มันจะเกิดคำถามขึ้นมาทันทีว่า แล้วเราจะเทสมันยังไง ถ้ามันเปลี่ยนตลอดเวลา คำตอบของคำถามนั้นก็คือ เราต้อง Mock มันครับ ซึ่ง Python มี standard library ไว้จัดการเรื่องนี้ครับคือ unittest.mock.patch\u003c/p\u003e\n\u003cp\u003ePatch นั้นมีหลายท่า ก่อนหน้านี้ผมเคยเล่าให้ฟังบางส่วนแล้วว่าเราจะจัดการกับการ Patch หลายๆ module ยังไง ซึ่งใช้ \u003cstrong\u003eExitStack()\u003c/strong\u003e มาช่วยในการจัดการ context สนใจไปอ่านต่อได้ที่นี่ครับ\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"/python-exitstack/\"\u003ePython - ExitStack แบบสั้นๆ\u003c/a\u003e\nวันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ มาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes โอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager\n— Yothinix, Yothin Muangsommuk\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eแต่จริงๆ เราสามารถใช้ patch ได้ถึง 3 แบบเลย แล้วแต่สถานการณ์ครับ\u003c/p\u003e","title":"Patch ยังไงให้อ่านรู้เรื่อง"},{"content":"วันที่ 7 ของ #PythonTricksEveryday วันนี้ขอเสนอ ExitStack() ครับ\nมาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes\nโอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager เนี่ยจะเป็นตัวจำกัดการเข้าถึงและปล่อย Resource หนึ่งๆ ซึ่ง keyword ที่เราคุ้นเคยที่สุดน่าจะเป็น with ใช่มั้ยครับ ตัว Resource ที่เราพูดถึงกันนี้ง่ายที่สุดก็น่าจะเป็นไฟล์ หรือการต่อ database อะไรเทือกนี้ใช่มั้ยครับ\nทีนี้เวลาเราจะเปิดไฟล์หลายๆ ไฟล์ สิ่งที่เกิดขึ้นคือมันก็จะเกิดอาการ with ซ้อน with ไปเรื่อยๆ จนกระทั่ง Python 3.3 ได้เพิ่ม ExitStack() เข้าไปใน contextlib ครับโดย ExitStack() ตัวนี้จะช่วยจัดการเกี่ยวกับ context manager ได้ดียิ่งขึ้นกว่า nested with ที่เคยใช้กันมา\nแต่ในเคสที่ผมกำลังพูดถึงนี่คือการเขียน Unit Test ครับและเป็นเทสที่มี Mock เข้ามาเกี่ยวข้องด้วย และที่พิเศษกว่านั้นคือต้อง Mock เยอะๆ ด้วยครับ\nจะเห็นว่า example_function เรามีของที่มี side effect แล้วเราต้อง Mock() อยู่สองอย่างใช่มั้ยครับคือ randint และ datetime.now() แต่ก่อนตอนผมเขียน Unit Test ที่ต้อง Mock อะไรแบบนี้ ผมจะไปเหมือน test case แรกเลยครับ คือใช้เป็น decorator patch() แปะอยู่บนหัวของ test case วิธีนี้ใช้ง่ายครับ แต่จะเริ่มมีปัญหาตามมาเมื่อเริ่ม Mock() มากกว่าหนึ่งตัว\nปัญหาแรกคือ มือใหม่จะสับสนมากว่าที่ patch เรียงๆ กันเนี่ย argument ของ test case มันคือตัวไหน สำหรับคนที่ยังไม่รู้นะครับ argument ของ decorator จะเรียงจากในไปนอกครับ\nปัญหาที่สองคือ ถ้า decorator เยอะมากขึ้นเรื่อยๆ เราจะเริ่มหา test case ไม่เจอครับ เพราะ function signature เรามีแต่ decorator แถมยิ่ง patch decorator มากตัว arguments ของ test case ก็มากตามไปด้วยครับ\nจะเห็นว่าในเคสที่สองผมใช้ ExitStack() ร่วมกับ context manager ในการประกาศ patch แทน ซึ่งถามว่าบรรทัดมันน้อยลงมั้ย ก็ไม่ แต่สิ่งที่เราได้กลับมาคือชื่อ test case หรือ function signature เรา clean มากครับ ทำให้มองหาเทสที่จะเจอได้ง่าย และเรายังสามารถแบ่ง statement ในเทสเป็น Arrange / Act / Assert ได้เหมือนเดิมครับ\nต้องบอกว่า Trick นี้ผมไปเจอโดยบังเอิญ เพราะเกิดจากปัญหาที่ผมพูดถึงข้างต้นนั่นแหละครับ จริงๆ พี่ @zkan เคยเขียน Blog พูดถึงเรื่องนี้ตอนผมเอามาใช้กับทีม Pronto Tools ได้ซักพัก ถ้าใครอ่านตรงนี้แล้วงงๆ ลองไปอ่านที่พี่กานต์เขียนได้ครับ\nReference - Blog เกี่ยวกับ ExitStack() โดย @zkan https://bit.ly/2Kegi3D\n- https://docs.python.org/3/library/contextlib.html\nOriginal post at: https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303/233059164080944/?type=3\u0026amp;theater\n","permalink":"https://yothinix-com.pages.dev/python-exitstack/","summary":"\u003cp\u003eวันที่ 7 ของ \u003ca href=\"https://www.facebook.com/hashtag/pythontrickseveryday?__eep__=6\u0026amp;__tn__=*NK*F\"\u003e#PythonTricksEveryday\u003c/a\u003e วันนี้ขอเสนอ ExitStack() ครับ\u003cbr\u003e\nมาช้าหน่อยนะครับวันนี้ มัวแต่ตื่นเต้น 1,000 likes\u003c/p\u003e\n\u003cp\u003eโอเค เข้าเรื่องดีกว่า ก่อนจะไปรู้จัก ExitStack เราต้องรู้จักสิ่งที่เรียกว่า context manager ก่อนครับ context manager เนี่ยจะเป็นตัวจำกัดการเข้าถึงและปล่อย Resource หนึ่งๆ ซึ่ง keyword ที่เราคุ้นเคยที่สุดน่าจะเป็น with ใช่มั้ยครับ ตัว Resource ที่เราพูดถึงกันนี้ง่ายที่สุดก็น่าจะเป็นไฟล์ หรือการต่อ database อะไรเทือกนี้ใช่มั้ยครับ\u003cbr\u003e\n\u003cbr\u003e\nทีนี้เวลาเราจะเปิดไฟล์หลายๆ ไฟล์ สิ่งที่เกิดขึ้นคือมันก็จะเกิดอาการ with ซ้อน with ไปเรื่อยๆ จนกระทั่ง Python 3.3 ได้เพิ่ม ExitStack() เข้าไปใน contextlib ครับโดย ExitStack() ตัวนี้จะช่วยจัดการเกี่ยวกับ context manager ได้ดียิ่งขึ้นกว่า nested with ที่เคยใช้กันมา\u003cbr\u003e\n\u003cbr\u003e\nแต่ในเคสที่ผมกำลังพูดถึงนี่คือการเขียน Unit Test ครับและเป็นเทสที่มี Mock เข้ามาเกี่ยวข้องด้วย และที่พิเศษกว่านั้นคือต้อง Mock เยอะๆ ด้วยครับ\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eจะเห็นว่า example_function เรามีของที่มี side effect แล้วเราต้อง Mock() อยู่สองอย่างใช่มั้ยครับคือ randint และ datetime.now() แต่ก่อนตอนผมเขียน Unit Test ที่ต้อง Mock อะไรแบบนี้ ผมจะไปเหมือน test case แรกเลยครับ คือใช้เป็น decorator patch() แปะอยู่บนหัวของ test case วิธีนี้ใช้ง่ายครับ แต่จะเริ่มมีปัญหาตามมาเมื่อเริ่ม Mock() มากกว่าหนึ่งตัว\u003cbr\u003e\n\u003cbr\u003e\nปัญหาแรกคือ มือใหม่จะสับสนมากว่าที่ patch เรียงๆ กันเนี่ย argument ของ test case มันคือตัวไหน สำหรับคนที่ยังไม่รู้นะครับ argument ของ decorator จะเรียงจากในไปนอกครับ\u003c/p\u003e","title":"Python - ExitStack แบบสั้นๆ"},{"content":"ในโอกาสที่เพจ เขียนงูให้วัวกลัว ครบ 1000 likes ผมเลยคิดได้ว่า เออ อยู่ดีๆ ผมก็มาทำเพจเอามันส์ อยากเขียนอะไรก็เขียน แล้วก็มาสงสัยกับตัวเองบางครั้งว่า ทำไมเราถึงมีความรู้สึกอยากจะทำเพจนี้มากขนาดนี้ ผมเลยมองย้อนกลับมาหาตัวเองว่า ทำไม เราถึงชอบภาษานี้มากขนาดนี้ มันมีเหตุผลอะไร ผมจะพาไปไล่ดูครับว่าทำไมผมถึงรักภาษานี้มากและอาจจะเป็นเหตุผลให้คุณรักภาษานี้เหมือนกันก็ได้\nBeautiful is better than ugly 💄 hello world แบบ Python นะครับ\nส่วนแรกที่ผมชอบเกี่ยวกับภาษานี้คือ Semantic มันครับ เรื่องนี้ต้องย้อนไปถึง Design Philosophy ของตัวภาษาเลยว่ามันถูกออกแบบมาให้เป็นภาษาที่อ่านได้ง่ายมากๆ โดยใช้ keyword ภาษาอังกฤษ แทนที่จะใช้เครื่องหมายต่างๆ รวมไปถึงใช้ Indentation แทนที่จะใช้ curry bracket ในการกำหนด scope เป็นต้น\nด้วยตัวภาษาเองยังเป็นภาษา Multi-paradigm ทำให้รองรับรูปแบบการเขียนโปรแกรมหลายรูปแบบมากตั้งแต่ Imperative, Object Oriented, Functional, Procedural และ Reflective ทำให้เราไม่ถูกจำกัดแนวคิดในการแก้ปัญหาต่างๆ ด้วยภาษานี้ถึงแม้มันจะขัดกับ Zen of Python ข้อ There should be one — and preferably only one — obvious way to do it. ก็เถอะ\nนอกจากนี้แล้วตัวภาษาเองยังมี Coding Style (PEP8), Zen of Python (PEP20), Linter (Flake8, PyLint) รวมไปถึง Formatter (yapf, Black) ฯลฯ อีกหลายอย่างที่ช่วยเราในเรื่อง Code Convention ถึงแม้ว่าภาษาสมัยใหม่หลายภาษาจะมีของพวกนี้มาให้ในตัว แต่อย่างน้อย Python ก็มีเครื่องมือพวกนี้ให้เลือกใช้หลากหลาย และทำให้โค้ดเราเป็นไปในทางเดียวกันครับ\nCheeseShop 🧀 ถ้าใครไม่รู้จัก CheeseShop นะครับ มันคือ codename ของ PyPI หรือ Python Package Index เอง ส่วนนี้สำคัญยังไง สิ่งที่สำคัญอย่างนึงของทุกภาษาคือ Package repository ครับ ทำให้เราทำงานแบบ Modular programming ได้ครับ\nModular Programming คือ concept ที่ว่าเราไม่ต้องเขียนทุกอย่างขึ้นมาเองใหม่ทั้งหมด ปัญหาบางปัญหามีคนแก้ไปแล้ว เราก็ไปเอาโค้ดเค้ามาใช้ ซึ่ง ณ ตอนที่เขียนอยู่นี่ PyPI มี Package ให้เราเลือกใช้อยู่ทั้งสิ้น 147,551 projects ครับ ไม่น้อยเลยทีเดียว ตั้งแต่ Library เล็กๆ ที่ใช้แก้ปัญหาดึงค่าของจาก Dictionary ออกมา ไปจนถึง Library ในการทำ Machine Learning คำนวณกลศาสตร์ระหว่างดาวเคราะห์เลยทีเดียว\nจริงๆ PyPI เคยเป็นหนึ่งในจุดอ่อนของ Python เหมือนกันนะครับ ด้วยหน้าตาที่โบราณมาก จนผมไม่เคยคิดจะไปหา Project ในนั้นเลย แต่เมื่อไม่กี่เดือนก่อน PyPI เพิ่ง Rewrite ใหม่ทั้งหมดบน Pyramid Framework แล้วกลายเป็น PyPI อย่างที่เราเห็นทุกวันนี้ครับ น่าใช้ขึ้นมากเลยทีเดียว\nหน้าตาปัจจุบันของ https://pypi.org/ ครับ\nCommunity 🙋‍♂️🙋‍♀️ ความเจ๋งของ Python Community อย่างนึงคือ มันไม่ค่อยมีดราม่าครับ นานๆ ทีจะมี อย่างเช่นกรณี PEP 572 — Assignment Expressions และ Guido ประกาศลาพักไม่มีกำหนดจากตำแหน่ง BDFL ตลอดมาก็แทบไม่มีดราม่าเลยครับ นอกจากนั้นแล้วทั่วโลกยังมีงาน PyCon จัดตั้งแต่ United State มาจนถึง Australia และล่าสุดในไทยเราก็เพิ่งมีจัด PyCon Thailand ครับ\nThe Incredible Growth of Python When we focus on high-income countries, the growth of Python is even larger than it might appear from tools like Stack Overflow Trends. — Stack Overflow Blog, David Robinson\nในส่วนของการเติบโตนั้น Python เป็นภาษาที่มีอัตราการเติบโตเร็วที่สุดในปีนี้เลยครับ จาก Stack Overflow Trends ซึ่งมามองในอีกมุมนึง มันดีรึเปล่าหว่า เป็นเพราะมีคนไปถามเยอะ หรือตัวภาษามันมีปัญหาบางอย่าง เรื่องนี้ก็มองได้หลายมุมเหมือนกัน\nDjango 🎸 Django Reinhardt นักกีตาร์ (ชื่อ Framework เอามาจากคนนี้แหละ)\nอันนี้เพราะว่างานผมอาจจะเกี่ยวข้องกับทาง Web Application เลยมีเรื่องนี้เข้ามาเกี่ยวข้องครับ คือ Django เนี่ยเป็น Web Framework ที่เป็นหนึ่งใน Goto ถ้าใช้ Python ครับอีกตัวก็ Flask แต่ก็แล้วแต่ลักษณะงานด้วย ตัว Django เองเนี่ย สามารถสร้าง Databases แล้วทำเป็น REST API และมีหน้า Admin สวยๆ ไว้จัดการภายในไม่กี่นาที ต้องขอบคุณพลังของ Django REST Framework ด้วยอีกตัวนึงที่ทำให้การสร้าง REST API มันไวขนาดนี้\nนอกจากนั้นแล้วตัว Django เองยัง Extends ได้อีกเยอะมาก ซึ่งมากแค่ไหนก็ลองดูได้ที่เว็บนี้เลยครับ\nGitHub - wsvincent/awesome-django: A curated list of awesome things related to Django A curated list of awesome things related to Django - GitHub - wsvincent/awesome-django: A curated list of awesome things related to Django — GitHub, wsvincent\nส่วนเรื่อง Maturity ก็ไม่ต้องกังวลครับเพราะยังมีบริษัทระดับโลกยังใช้งาน Django อยู่คือ Instagram และตัว Framework เองก็ยังพัฒนาอยู่เรื่อยๆ ทำให้ไม่ต้องห่วงว่าวันนี้ พรุ่งนี้ Django ที่เราใช้มันจะตกยุคนะครับ\nเท่าที่คิดออกมันก็ประมาณนี้ครับ ช่วงที่ผ่านมาอาจจะมีปันใจไปให้ภาษาอื่นบ้าง แต่ภาษานี้ก็เป็นที่หนึ่งในใจมาตลอดครับ สุดท้ายนี้ต้องขอบคุณทุกคนมากๆ นะครับที่มารับชมเพจเล็กๆ เพจนี้ ใจผมเองก็อยากจะเล่าเรื่องต่างๆ เกี่ยวกับตัวภาษาออกมาให้มากๆ เพราะโดยตัวภาษาเองก็มีอะไรให้พูดถึงได้ไม่หมด ไม่สิ้นเลยครับ แล้วพบกันในเพจ สวัสดีครับ\nเขียนงูให้วัวกลัว เขียนงูให้วัวกลัว. 5,199 likes · 1 talking about this. เล่าทุกเรื่องเกี่ยวกับไพธอน ตกลงวัวตัวผู้หรือตัวเมีย — Home\nปล.ตอนนี้ทางเพจมีกิจกรรมให้ร่วมสนุกกันนะครับ เพียงแค่เขียนบทความเกี่ยวกับภาษา Python อะไรก็ได้ แล้วแปะไว้ใน comment ของโพสนี้ https://bit.ly/2M7Jqvb ภายในวันที่ 6 สิงหาคมนี้ ทางผมจะสุ่มแจก Key ของ PyCharm Profession Edition: 6 month นะครับ มาร่วมสนุกกันได้ครับ\nOriginal Post at: https://yothinix.medium.com/why-i-love-python-so-much-a47e24855088\n","permalink":"https://yothinix-com.pages.dev/why-i-love-python-so-much/","summary":"\u003cp\u003eในโอกาสที่เพจ \u003ca href=\"https://www.facebook.com/writepythontoscarecow/\"\u003eเขียนงูให้วัวกลัว\u003c/a\u003e ครบ 1000 likes ผมเลยคิดได้ว่า เออ อยู่ดีๆ ผมก็มาทำเพจเอามันส์ อยากเขียนอะไรก็เขียน แล้วก็มาสงสัยกับตัวเองบางครั้งว่า ทำไมเราถึงมีความรู้สึกอยากจะทำเพจนี้มากขนาดนี้ ผมเลยมองย้อนกลับมาหาตัวเองว่า ทำไม เราถึงชอบภาษานี้มากขนาดนี้ มันมีเหตุผลอะไร ผมจะพาไปไล่ดูครับว่าทำไมผมถึงรักภาษานี้มากและอาจจะเป็นเหตุผลให้คุณรักภาษานี้เหมือนกันก็ได้\u003c/p\u003e\n\u003ch1 id=\"beautiful-is-better-than-ugly-\"\u003eBeautiful is better than ugly 💄\u003c/h1\u003e\n\u003cp\u003e\u003cimg src=\"/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp\"\n       srcset=\"/why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_9a9ecb2cfaae3566.webp 480w, /why-i-love-python-so-much/1-dypAPjPDUB2bVoMJzkMtfw_hu_1586b6ed741baad9.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"185\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003ehello world แบบ Python นะครับ\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eส่วนแรกที่ผมชอบเกี่ยวกับภาษานี้คือ Semantic มันครับ เรื่องนี้ต้องย้อนไปถึง Design Philosophy ของตัวภาษาเลยว่ามันถูกออกแบบมาให้เป็นภาษาที่อ่านได้ง่ายมากๆ โดยใช้ keyword ภาษาอังกฤษ แทนที่จะใช้เครื่องหมายต่างๆ รวมไปถึงใช้ Indentation แทนที่จะใช้ curry bracket ในการกำหนด scope เป็นต้น\u003c/p\u003e\n\u003cp\u003eด้วยตัวภาษาเองยังเป็นภาษา Multi-paradigm ทำให้รองรับรูปแบบการเขียนโปรแกรมหลายรูปแบบมากตั้งแต่ Imperative, Object Oriented, Functional, Procedural และ Reflective ทำให้เราไม่ถูกจำกัดแนวคิดในการแก้ปัญหาต่างๆ ด้วยภาษานี้ถึงแม้มันจะขัดกับ Zen of Python ข้อ \u003cem\u003eThere should be one — and preferably only one — obvious way to do it.\u003c/em\u003e ก็เถอะ\u003c/p\u003e","title":"Why I love Python so much"},{"content":"วันที่ 2 ของ #PythonTricksEveryday นะครับ ไหนๆ ก็เป็นวันสุดท้ายของการทำงานก่อนจะถึงวันหยุดยาว ขอแนะนำด้วย Tricks เล็กๆ ที่จะช่วยให้การทำงานกับ Multiline String เราดีขึ้นครับ\nสมมติว่าเรามี String ยาวๆ ที่ต้องมี Indent สวยๆ เช่น Email หรือ Code snippet อย่างในภาพ แล้วเราต้องการนำมันไปใช้งานเช่นส่งอีเมล์หรือ Print report อะไรแบบนี้\nจะเห็นว่าพอ print ค่าออกมาแล้ว string ที่เราเก็บไว้มี space ติดมาด้วย\nสิ่งที่เกิดขึ้นคือ Multiline String ของ Python จะนับ tab ที่เราเว้นไว้ทางซ้ายด้วย เหมือนในฟังก์ชั่น process_something() ซึ่งถ้าเราไม่อยากให้มันเยื้องแล้ว Print ออกมาสวยๆ เราก็ต้องทิ้งเยื้องไป เหมือนในฟังก์ชั่น process_something_without_padding() ซึ่งพอเราทำแบบนี้ ผมว่าทุกคนน่าจะรู้สึกทันทีว่า เออมันเวิร์คนะแต่ Indent มั่วไปหมดเลย พ้น definition ของ function ไปอีก ยิ่งถ้าเป็น Method ที่อยู่ใน class ยิ่งไม่อยากจะคิดเลย\nถ้าจะกำจัด space ข้างหน้า string เราวิธีทั่วไปก็ทำแบบนี้ครับ\nทีนี้ถ้าเรายังอยากเก็บ Multiline String โดยที่ยังรักษา indent ของ function เราให้เป็นไปในทางเดียวกันอยู่ เราก็มีตัวเลือกหลายทางครับเช่น เอาไปเก็บแยกเป็นตัวแปรไว้ข้างนอก function ไปเลย หรือโหลดจากไฟล์อื่นเข้ามาอ่านก็ได้ แต่ผมคิดว่าการทำแบบนั้นมันเป็นแค่การเลี่ยงปัญหา ไม่ใช่การแก้ปัญหาจริงๆ\nPython มีวิธีในการแก้ปัญหาเรื่องนี้ครับ โดยใน standard library ที่ติดตัวมากับภาษามี Library ตัวนึงที่ชื่อว่า textwrap เอาไว้ทำงานเกี่ยวกับเรื่องแนวนี้ ซึ่งสิ่งที่เราต้องการก็คือ method ที่ชื่อว่า dedent ครับ เมื่อเราครอบ Multiline String ด้วย textwrap.dedent() เนี่ย สิ่งที่มันทำก็คือ มันจะลบ Leading space ออกจาก string ของเราทุกบรรทัดครับ ซึ่งทำให้เรากลับมาเขียน Multiline String สวยๆ ได้แบบฟังก์ชั่น process_something_with_dedent() เลยครับ\nแบบใช้ textwrap.dedent() จะเห็นว่า space ข้างหน้าถูกลบหายไป แล้วยังรักษา indent ถัดมาอยู่ด้วย\nจริงๆ textwrap library นี่ยังทำอะไรได้อีกหลายอย่างเลยนะครับ สนใจก็คลิกไปอ่าน Official document ได้ที่นี่เลยครับ\ntextwrap — Text wrapping and filling — Python 3.7.12 documentation\nOriginal post at: https://yothinix.medium.com/dedent-your-multiline-string-b7fc8f41b286\n","permalink":"https://yothinix-com.pages.dev/python-dedent-your-multiline-string/","summary":"\u003cp\u003eวันที่ 2 ของ #PythonTricksEveryday นะครับ ไหนๆ ก็เป็นวันสุดท้ายของการทำงานก่อนจะถึงวันหยุดยาว ขอแนะนำด้วย Tricks เล็กๆ ที่จะช่วยให้การทำงานกับ Multiline String เราดีขึ้นครับ\u003c/p\u003e\n\u003cp\u003eสมมติว่าเรามี String ยาวๆ ที่ต้องมี Indent สวยๆ เช่น Email หรือ Code snippet อย่างในภาพ แล้วเราต้องการนำมันไปใช้งานเช่นส่งอีเมล์หรือ Print report อะไรแบบนี้\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp\"\n       srcset=\"/python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_5e24f6a3354edd98.webp 480w, /python-dedent-your-multiline-string/1-W1kbbb4iiGbP7KXb_BUwBQ_hu_128cbfc369b23ee7.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"527\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eจะเห็นว่าพอ print ค่าออกมาแล้ว string ที่เราเก็บไว้มี space ติดมาด้วย\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eสิ่งที่เกิดขึ้นคือ Multiline String ของ Python จะนับ tab ที่เราเว้นไว้ทางซ้ายด้วย เหมือนในฟังก์ชั่น process_something() ซึ่งถ้าเราไม่อยากให้มันเยื้องแล้ว Print ออกมาสวยๆ เราก็ต้องทิ้งเยื้องไป เหมือนในฟังก์ชั่น process_something_without_padding() ซึ่งพอเราทำแบบนี้ ผมว่าทุกคนน่าจะรู้สึกทันทีว่า เออมันเวิร์คนะแต่ Indent มั่วไปหมดเลย พ้น definition ของ function ไปอีก ยิ่งถ้าเป็น Method ที่อยู่ใน class ยิ่งไม่อยากจะคิดเลย\u003c/p\u003e","title":"Dedent your multiline string"},{"content":"วันที่ 1 ของ #PythonTricksEveryday นะครับ วันนี้เปิดด้วยหนึ่งในเทคนิคที่ พอรู้แล้วก็ใช้ได้ตลอดเลย มันคือ built-in function ที่ชื่อว่า all() และ any() ครับ ไปดูสถานการณ์เลยดีกว่า\nสถานการณ์ที่เรามักจะเจอกันบ่อยๆ คือ เราต้องเขียน if ที่มี condition เยอะมากๆ อย่างในตัวอย่างนี้ก็ 5 conditions ซึ่ง บางทีรูปแบบที่มันอยู่อาจจะอยู่ยากกว่านี้ก็ได้ เช่น เป็น if แยกกันหลายๆ อันหรือ if ซ้อนใน if ให้เราลองพยายาม normalize ให้มันเหลือ if เดียวแล้วให้ความสัมพันธ์ของมันเหลือแค่ and / or\nพอเรา normalize ความสัมพันธ์ของแต่ละ condition จนเหมือนภาพข้างบนแล้ว สิ่งที่เกิดขึ้นก็คือ Linter ด่าครับ ยาวเกิน 80 บรรทัดอะไรก็ว่าไป ซึ่งเราก็จะต้องตบมันเข้ามาให้ไม่เกิน 80 บรรทัด โค้ดข้างล่างนี้ผมใช้ Black ช่วย Format ให้นะครับหน้าตาก็จะประมาณนี้\nโอเค อ่านง่ายกว่าตะกี้หน่อยๆ พอเราเห็นแบบนี้ปั๊ป เห้ยนี้มัน List นี่นา เราต้องทำอะไรบางอย่างเกี่ยวกับ List ได้สิ ถ้าเราเอา and / or ออกไปอะไรจะเกิดขึ้นน้า\nสวัสดี All / Any all() / any() น่าจะเป็น built-in function ที่อยู่คู่บุญ Python มานาน นานแค่ไหนผมก็ไม่รู้เหมือนกัน เพราะตั้งแต่ผมมาเขียนมันก็มีให้ใช้แล้ว แต่เพิ่งมาตระหนักว่ามันใช้อย่างนี้ได้ก็ปีที่แล้วนี่เอง ตัว function มันจะทำงานแบบนี้ครับ (method เอามาจาก Official document นะครับ)\nตัว Signature ของทั้งสอง function นั้นรับ Iterable object เหมือนกันครับ ซึ่งถ้าไม่ใช่ object ที่เรา implement เองแล้วมี __iter__ กับ next() method เราก็ใช้ List / Tuple ธรรมดาๆ ได้ครับ\nคำอธิบายของ All คือ จะ return True ถ้าทุกค่าเป็น True หรือ iterable เราเนี่ยส่งมาเป็นค่าว่าง ส่วน Any จะสลับกันคือ จะ return True ถ้ามี element อย่างน้อยตัวนึงมีค่าความจริงเป็น True ถ้า iterable ว่างจะ return False\nทีนี้เราจะเอามันมาใช้กับ if ยาวๆ เราได้ไงครับ ไปดูตัวอย่างข้างล่างได้เลย\nจะเห็นว่าแทนที่ผมจะเชื่อมแต่ละ condition ด้วย and / or ผมก็ยัดมันใส่ List / Tuple เอาไว้เลย แล้วตรง if ผมก็ใช้ all ครอบ List / Tuple ของ condition เอา แค่นี้ก็เรียบร้อยครับ\nข้อควรระวัง เพราะว่าเราย้าย expression ไปไว้ใน predicates List / Tuple แล้วจะมีปัญหาใหม่ตามมาคือ ถ้า if ที่เราเขียนตอนแรกเราอิง lazy evaluation หมายถึง ถ้าพังตัวแรกแล้วดีดออกจาก if เลย ซึ่งส่วนใหญ่จะเป็นเคส and ถ้า condition ที่ตามมา depends กับ condition ก่อนหน้า โค้ดเราจะระเบิดทันทีครับ\nจากตัวอย่างนะครับ สมมติเรามีสถานการณ์คล้ายๆ แบบนี้คือ is_customer_active() และ is_vip_customer() ต้องการ customer_id ไม่งั้นระเบิดทั้งคู่ เราสามารถ move lazy evaluate มาเช็คใน predicate ก่อนได้ครับอย่างเช่น customer_id and is_customer_active(customer_id) ถ้า customer_id ไม่มีค่าเนี่ย expression นี้ก็จะเป็น False ไปเลย\nจบแล้วครับ ข้อควรระวังอีกข้อนึงที่อยากฝากไว้คือ เวลาเรารู้เทคนิคใหม่ๆ แล้ว พอเราพยายามเอาไป Apply กับปัญหาที่ตัวเองใช้ อย่าลืมย้อนกลับมาดูด้วยนะครับว่า ถ้าเทียบกันแล้ววิธีใหม่กับวิธีเก่า เราหรือทีมโอเคกับแบบไหนมากกว่ากัน มันไม่มีวิธีไหนที่แก้ปัญหาได้ทุกอย่างครับ เหมือนกับ any / all ก็ไม่เหมาะกับบาง Use case เพราะฉะนั้น ใช้ด้วยความระมัดระวังนะครับ\nOriginal post at: https://yothinix.medium.com/the-power-of-any-all-ba219ef5c6cf\n","permalink":"https://yothinix-com.pages.dev/the-power-of-any-all/","summary":"\u003cp\u003eวันที่ 1 ของ #PythonTricksEveryday นะครับ วันนี้เปิดด้วยหนึ่งในเทคนิคที่ พอรู้แล้วก็ใช้ได้ตลอดเลย มันคือ built-in function ที่ชื่อว่า all() และ any() ครับ ไปดูสถานการณ์เลยดีกว่า\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp\"\n       srcset=\"/the-power-of-any-all/1-G1PX7wqGzCchAo8-EQ5CJg_hu_8bf2ff2e000f114d.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"162\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eสถานการณ์ที่เรามักจะเจอกันบ่อยๆ คือ เราต้องเขียน if ที่มี condition เยอะมากๆ อย่างในตัวอย่างนี้ก็ 5 conditions ซึ่ง บางทีรูปแบบที่มันอยู่อาจจะอยู่ยากกว่านี้ก็ได้ เช่น เป็น if แยกกันหลายๆ อันหรือ if ซ้อนใน if ให้เราลองพยายาม normalize ให้มันเหลือ if เดียวแล้วให้ความสัมพันธ์ของมันเหลือแค่ and / or\u003c/p\u003e\n\u003cp\u003eพอเรา normalize ความสัมพันธ์ของแต่ละ condition จนเหมือนภาพข้างบนแล้ว สิ่งที่เกิดขึ้นก็คือ Linter ด่าครับ ยาวเกิน 80 บรรทัดอะไรก็ว่าไป ซึ่งเราก็จะต้องตบมันเข้ามาให้ไม่เกิน 80 บรรทัด โค้ดข้างล่างนี้ผมใช้ \u003ca href=\"https://github.com/ambv/black\"\u003eBlack\u003c/a\u003e ช่วย Format ให้นะครับหน้าตาก็จะประมาณนี้\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp\"\n       srcset=\"/the-power-of-any-all/1-Ta8sZe-W44kc8errZ7vvPw_hu_12d78e26eb7ff15.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"476\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e","title":"The Power of Any / All"},{"content":"สิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ\nสมมติเรามีฟังก์ชั่น process_something ที่ทำหน้าที่ยิง requests ไปหา service ข้างนอกแล้วคืนของออกมาเป็น dictionary หน้าตาประมาณนี้\nprocess_something.py\nถ้าเขียนแบบสมัยก่อน เราก็จะต้อง patch ตัว requests.get แล้วสร้าง Mock() object มารับ return_value หน้าตาประมาณนี้\nซึ่งพอทำแบบนี้บ่อยๆ เราก็เริ่มเห็น Pattern ซ้ำๆ ครับว่าต้อง Mock status_code นะ json() call นะหรือแม้กระทั่ง content type กับ headers ในบางเคส\nวิวัฒนาการถัดมาของการ mock requests คือ พอเราเห็น pattern ซ้ำๆ เราก็จับมันมาทำ utils function ครับ ซึ่งหน้าตามันก็จะออกมาประมาณนี้\nแต่วิธีนี้ก็ยังต้องใช้ร่วมกับ assert_called_once_with เพื่อที่จะรับประกันว่าการที่เรา mock เนี่ยมันถูกใช้งานทุกครั้ง ไม่ใช่ mock free\nResponses ผมไปเจอ Package นี้ตอนกด Discovery ใน GitHub แล้วคน Star เยอะมาก (ณ เวลาเขียนก็ 1955 Stars) แล้วคนสร้างก็ไม่ใช่ใครที่ไหนไกล เป็น Sentry ซึ่งเป็น service ที่เราใช้ในการ catch exception เรานั่นเอง (สนใจอ่าน blog ว่าเราใช้ Sentry ยังไงบ้างได้ที่นี่ครับ) วิธีลงก็ง่ายมากครับเหมือน library Python ทั่วไปคือ\n$ pip install responses\nหลังจากเราลง Package นี้ไปแล้วเราก็สามารถใช้มันในการ Mock response object ของ HTTP request ที่เราเรียกได้แล้วครับ หน้าตาก็จะประมาณนี้\ntest_process_something.py\nจะเห็นว่าหน้าตา signature ของ responses.add ค่อนข้างจะใกล้เคียงกับ ที่เราเคย mock ก่อนหน้านี้เลยคือรับ HTTP METHOD, URL, JSON return และ status code ซึ่งตัว responses เองเนี่ยสามารถใช้ได้ทั้งแบบ decorator แบบในภาพและแบบ context manager ผ่าน responses.RequestsMock() ก็ได้ครับ\nความเจ๋งอีกอย่างนึงที่ responses ทำให้เราก็คือ เราไม่ต้องมานั่งเช็คว่า assert_called_once_with ตัว mock request เราแล้วครับ เพราะว่าตัว Library เองจะจัดการให้เลยผ่าน flag ที่ชื่อว่า assert_all_requests_are_fired ซึ่งค่า default ของมันจะเป็น True อยู่แล้ว แต่เราจะใช้ความสามารถนี้ได้ต้องใช้ responses.RequestsMock() หรือใช้ผ่าน context manager นะครับ\nนอกจากจะ assert request ให้เราแล้ว อีกความสามารถนึงที่เจ๋งมากคือ เราสามารถเพิ่ม callback function ให้มัน return response แบบ dynamic ได้ครับ หน้าตาก็ประมาณนี้ (ตัวอย่างผมเอามาจาก README.md ของ Library นะครับ)\nยังมีความสามารถอื่นๆ อีกนะครับที่ผมยังไม่ได้พูดถึง แต่ที่พูดถึงมานี่คือ Use Case ที่ทีมเราเอามาใช้แล้ว มันสะดวกและสวยมาก ถ้าอยากศึกษาเพิ่มเติมตามไปดูได้ที่ GitHub repo ของ Responses เลยครับ\nGitHub - getsentry/responses: A utility for mocking out the Python Requests library. A utility for mocking out the Python Requests library. - GitHub - getsentry/responses: A utility for mocking out the Python Requests library. — GitHub, getsentry\nOriginal post at: https://yothinix.medium.com/mock-requests-แบบสวยๆ-ด้วย-responses-736e5f74b7f9\n","permalink":"https://yothinix-com.pages.dev/mock-python-request-with-responses/","summary":"\u003cp\u003eสิ่งหนึ่งที่เราเจอไม่ว่าจะช้าหรือเร็วคือ เมื่อเขียน Python ไปซักพักเราต้องยุ่งกับการยิง HTTP request ไปหา service ข้างนอก ซึ่ง Library ที่นิยมที่สุดในการทำสิ่งนี้ใน Python ก็คงหนีไม่พ้น requests นะครับ\u003c/p\u003e\n\u003cp\u003eสมมติเรามีฟังก์ชั่น process_something ที่ทำหน้าที่ยิง requests ไปหา service ข้างนอกแล้วคืนของออกมาเป็น dictionary หน้าตาประมาณนี้\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp\"\n       srcset=\"/mock-python-request-with-responses/1-cbENO9XyXZ-BBITVEfzeog_hu_6d35393857ada90f.webp 464w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"464\" height=\"354\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eprocess_something.py\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eถ้าเขียนแบบสมัยก่อน เราก็จะต้อง patch ตัว requests.get แล้วสร้าง Mock() object มารับ return_value หน้าตาประมาณนี้\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp\"\n       srcset=\"/mock-python-request-with-responses/1-uaFBxo2JLN2fwgswycfd1A_hu_bdb37363f45e44a1.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"326\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eซึ่งพอทำแบบนี้บ่อยๆ เราก็เริ่มเห็น Pattern ซ้ำๆ ครับว่าต้อง Mock status_code นะ json() call นะหรือแม้กระทั่ง content type กับ headers ในบางเคส\u003c/p\u003e\n\u003cp\u003eวิวัฒนาการถัดมาของการ mock requests คือ พอเราเห็น pattern ซ้ำๆ เราก็จับมันมาทำ utils function ครับ ซึ่งหน้าตามันก็จะออกมาประมาณนี้\u003c/p\u003e","title":"Mock requests แบบสวยๆ ด้วย responses"},{"content":"จากวันเสาร์ - อาทิตย์นี้พี่ @zkan ชวนมาทำ Hackathon กันที่ Pronto Tools เลยเป็นโอกาสเหมาะว่าจะทำอะไรที่มัน Out of comfort zone ซักหน่อยแล้วส่วนตัวผมอยากจะเขียน Elixir มานานหลายปีมากเลยเป็นที่มาของ Blog นี้ครับ\nเอาจริงๆ จนจบวันนี้ผมยังไม่รู้เลยว่าที่ผมเขียนไปมันถูก / ผิด idiom ของ Elixir ไปมากแค่ไหน แต่แค่อยากจะมาพูดถึงสิ่งที่ประทับใจในตัวภาษาจากมุมมองของคนที่เขียนแต่ Python เป็นหลักในชีวิต\nProject Structure mix.exs\nอยากแรกเลยที่เจอพอคิดว่าจะใช้ Elixir Implement คือ จะวางโครงสร้างมันยังไง จะเขียนเป็น script.ex เลย หรือต้องทำยังไง หลังจากลองผิดลองถูกอยู่ซักแปป ถึงรู้ว่าภาษามีสิ่งที่เรียกว่า Mix ซึ่งเป็น Build tools หลักของภาษาสามารถสร้างได้โดยใช้คำสั่ง\n$ mix new \u0026lt;name\u0026gt;\nซึ่งพอ Generate ออกมาแล้วมันจะสร้าง structure project ให้เลยตามชื่อที่เราตั้ง ซึ่งมี mix.exs เป็น Project description file อารมณ์น่าจะคล้ายๆ package.json ของ Node สร้าง module เราให้ด้วยจะอยู่ใน lib/\u0026lt;name\u0026gt;.ex สร้างไฟล์เทสของ module เราให้ด้วยที่ test/\u0026lt;name\u0026gt;_test.exs รวมถึงสร้าง README.md ให้เราด้วยอัตโนมัติเลย\nTask Runner lib/mix/tasks/main.ex\nคำถามต่อมาหลังจากสร้าง Project ขึ้นมาได้แล้วก็คือ แล้วจะรันมันยังไง? ผมพอจะรู้มาบ้างว่ามันมี iex (Interactive Elixir) ซึ่งเทียบได้ว่าเป็น REPL ของภาษานี้ก็ได้ แต่จะให้ iex มาสั่งรัน module เราทุกครั้งมันก็ค่อนข้างจะพิมพ์เยอะ Requirement ผมเองคืออยากได้ Task runner มาไว้รันคำสั่งให้ซึ่ง มันมีวิธีทำครับ แล้วง่ายมากด้วย\nวิธีคือไปสร้าง Directory ตามนี้ครับ /lib/mix/tasks/ เสร็จแล้วข้างในนั้นสร้าง module มาตัวนึงชื่ออะไรก็ได้ในที่นี้ผมตั้งชื่อมันว่า main.ex ข้างใน module ก็ตามภาพข้างบนครับ จะเห็นว่ามัน use Mix.Task ประกอบกับ method run หลังจากนั้นใน method run ให้เราใส่ Method ที่เราจะรันลงไป แค่นี้ก็เรียบร้อย วิธีรันก็คือ\n$ mix main Formatter ความเจ๋งของ mix project อีกอย่างก็คือมันมี Formatter ในตัวครับ​ ซึ่งผมก็ไม่รู้ว่ามันทำงานยังไงนะ แต่แค่เราสั่งคำสั่งข้างล่าง โค้ดเราก็จะจัดระเบียบให้เป็นไปในแนวทางเดียวกันละ ไม่ต้องลง module แยกอย่าง YAPF อะไรแบบนี้เลย\n$ mix format Configuration แน่นอนว่าเวลาเราทำ App ซักแอพถ้ามีการต้องติดต่อกับ 3rd Parties มันหลีกเลี่ยงไม่ได้ครับที่เราจะต้องหาทางใช้ Secret บางอย่างเช่น​ Username, Password หรือ Access Token กับโค้ดของเรา ซึ่งปกติตอนผมเขียน Python ก็เก็บมันไว้ใน .env ให้ Pipenv มันอ่านออกมาให้ แต่ Elixir มีวิธีต่างออกไปครับ\nวิธีของ Elixir คือเราจะสร้าง config file ขึ้นมา แล้วสร้าง config เก็บไว้เป็นกลุ่มๆ (อันนี้ก็ไม่รู้จะเรียกว่าไงเหมือนกัน) เสร็จแล้วในโค้ดของเราก็เรียกผ่าน Application.get_env(\u0026lt;group\u0026gt;, \u0026lt;key\u0026gt;) ก็เป็นอันเรียบร้อยครับ\nModule มาดูที่ Module ที่มัน Generate มาให้บ้าง ผมยอมรับเลยครับว่าแว็บแรกที่มองนี่คือ อ่อ มันก็ class นี่หว่า จริงๆ มันน่าจะเทียบกันไม่ได้โนะ แต่ Concept หลายอย่างก็ใกล้เคียงกัน อย่างแรกเลยที่ชอบคือ Attribute ครับถ้าเป็น Python เราก็เขียนมันไปโต้งๆ ใน class นะแหละเหมือนเป็นตัวแปรตัวนึง แต่กับ Elixir ตัว Module attribute เราต้องเพิ่ม @ ข้างหน้ามันครับ\nAnonymous function เอาจริงๆ ก็ไม่เคยคิดว่าจะได้เขียน Anonymous function บ่อยๆ เพราะส่วนตัวไม่ชอบเพราะอ่านไม่ค่อยรู้เรื่อง (ใน Python หนะ) แต่ใน Elixir นี่ผมค่อนข้างชอบทีเดียว เพราะมันคล้ายๆ กับ Arrow function ที่เขียนบ่อยๆ ใน JS เพียงแต่ว่ามันจะมี keyword fn เอาไว้ข้างหน้าไว้ประกาศว่ามันคือ function นะ แล้วมี end ปิดตรงท้ายด้วย หน้าตาก็ประมาณนี้ครับ\nPipe Operator ✨ Pipe Operator (|\u0026gt;) นี่น่าจะเป็นสิ่งที่ผมชอบที่สุดในตัวภาษานี้แล้ว และเป็นเหตุผลหลักให้อยากเขียนมาตลอดด้วย หลักการของมันง่ายๆ มากครับคือมันจะรับ return value ของ function ทางซ้าย (หรือก่อนหน้า) ของ Pipe แล้วเอามาเป็น First argument ของ function ทางขวา หรือถ้า function ตัวที่รับต้องรับ arguments มากกว่าหนึ่งตัว เราก็สามารถเขียน arguments ตัวต่อๆ ไปใส่ได้เลยครับ มันจะรู้เองว่า arguments ตัวแรกจะถูกยัดมาผ่าน Pipe\nผมพบว่าพอเราเริ่มใช้ Pipe บ่อยขึ้นเรื่อยๆ เราจะเริ่มมองทุกอย่างให้เป็น function ที่เล็กที่สุดครับ ที่เราทำแบบนั้นเพราะอยากจะ Chain ให้มันอยู่ใน Pipe แล้วมันรู้สึกดีมาก อ่านง่ายด้วย\nSignils อันนี้เป็นสิ่งใหม่มากในชีวิตครับ ความอยากเขียน Elixir มาหลายปีก็ไม่เคยทำให้เรามาพบเจอกันจนกระทั่งวันนี้ Signils นี่เป็นอะไรที่ทำให้เราเขียน string, regex ฯลฯ ได้ง่ายขึ้นมากครับ หน้าตาก็ประมาณนี้\nString and IO ขอบันทึกเก็บไว้หน่อยละกันว่า String ของ Elixir มีทุกอย่างครบเครื่องอย่างที่ String ในภาษาอะไรก็ตามควรจะมีเช่น Multiline string, String interpolation ให้ครบเครื่อง\nส่วน IO น่าจะเป็นวิธี basic ที่สุดในการ debug โนะ ซึ่งตอนแรกสุดเนี่ยผมนึกว่า IO.puts มันจะ support ทุกอย่างแต่พอเขียนไป อ่าวเห้ย ถ้าไม่ใช่ string ต้องใช้ IO.inspect ละก็ละเอียดไปอย่าง\nDebugger ถึงแม้ IO.inspect จะเป็นวิธี debug ที่ง่ายที่สุด แต่ผมยอมรับเลยว่าผมติด debugger ใน Python มาคือ import ipdb; ipdb.set_trace() แล้วพยายามอยากหาวิธีที่จะใช้ท่าเดียวกันได้ โชคดีที่ Elixir ก็มีอะไรบางอย่างคล้ายๆ กันคือ IEx.pry\nวิธีการของมันก็คือ เราไปแปะ Snippet ไว้ตรงโค้ดที่เราต้องการจะหยุดมันเสร็จแล้วเราสั่ง iex -S \u0026lt;task\u0026gt; มันก็จะสั่งรัน task ที่เราสร้างไว้แล้วหยุดตรงที่เราแปะ debugger ไว้ครับ มีประโยชน์มากๆ\nConclusion ถ้าจะมีอะไรที่รู้สึกชอบ จากการที่ใช้ภาษาใหม่ๆ Implement อะไรบางอย่างก็คือ มันได้แนวคิดใหม่ๆ ในการแก้ปัญหานี่แหละครับ มีประโยชน์มากๆ ตอนนี้เลยชอบเขียน utility function เล็กๆ เอาไว้แก้ปัญหาย่อยๆ แล้วเอามารวมกันเป็น Pipeline ก็แก้ปัญหาอะไรได้เร็วดี (เขียนเทสง่ายด้วย)\nอ่อเกือบลืมบอก Hackathon โปรเจ็คเล็กๆ ผมนี่แค่ต้องการสร้างอีเมล์ Sprint Summary ตอนจบ Sprint นะครับ ปกติเราใช้ Milestone + Issue ในการทำงานที่ Pronto อยู่แล้ว แต่ถ้ามี Script นี้ก็ทำให้ลดเวลาการเขียนอีเมล์ลงไปได้บ้าง โค้ดของโปรเจ็คอยู่ที่นี่นะครับ สนใจก็เปิด PR มาแก้ได้ครับผมหรือใครจะ Fork ไปพัฒนาต่อผมก็ยินดีครับ\nGitHub - yothinix/mssum: Milestone Summary - A Pronto’s hackathon project Milestone Summary - A Pronto’s hackathon project. Contribute to yothinix/mssum development by creating an account on GitHub. — GitHub, yothinix\nOriginal post at: https://yothinix.medium.com/a-day-with-elixir-dc41e21d68c6\n","permalink":"https://yothinix-com.pages.dev/a-day-with-elixir/","summary":"\u003cp\u003eจากวันเสาร์ - อาทิตย์นี้พี่ @zkan ชวนมาทำ Hackathon กันที่ Pronto Tools เลยเป็นโอกาสเหมาะว่าจะทำอะไรที่มัน Out of comfort zone ซักหน่อยแล้วส่วนตัวผมอยากจะเขียน Elixir มานานหลายปีมากเลยเป็นที่มาของ Blog นี้ครับ\u003c/p\u003e\n\u003cp\u003eเอาจริงๆ จนจบวันนี้ผมยังไม่รู้เลยว่าที่ผมเขียนไปมันถูก / ผิด idiom ของ Elixir ไปมากแค่ไหน แต่แค่อยากจะมาพูดถึงสิ่งที่ประทับใจในตัวภาษาจากมุมมองของคนที่เขียนแต่ Python เป็นหลักในชีวิต\u003c/p\u003e\n\u003ch1 id=\"project-structure\"\u003eProject Structure\u003c/h1\u003e\n\u003cp\u003e\u003cimg src=\"/a-day-with-elixir/1-QgdqLpwRMsc176hrMrLAdg_hu_d06454c861e2c101.webp\"\n       srcset=\"/a-day-with-elixir/1-QgdqLpwRMsc176hrMrLAdg_hu_1aa32778a41c3f0c.webp 480w, /a-day-with-elixir/1-QgdqLpwRMsc176hrMrLAdg_hu_d06454c861e2c101.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"1093\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003emix.exs\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eอยากแรกเลยที่เจอพอคิดว่าจะใช้ Elixir Implement คือ จะวางโครงสร้างมันยังไง จะเขียนเป็น script.ex เลย หรือต้องทำยังไง หลังจากลองผิดลองถูกอยู่ซักแปป ถึงรู้ว่าภาษามีสิ่งที่เรียกว่า Mix ซึ่งเป็น Build tools หลักของภาษาสามารถสร้างได้โดยใช้คำสั่ง\u003c/p\u003e\n\u003cp\u003e$ mix new \u0026lt;name\u0026gt;\u003c/p\u003e\n\u003cp\u003eซึ่งพอ Generate ออกมาแล้วมันจะสร้าง structure project ให้เลยตามชื่อที่เราตั้ง ซึ่งมี mix.exs เป็น Project description file อารมณ์น่าจะคล้ายๆ package.json ของ Node สร้าง module เราให้ด้วยจะอยู่ใน lib/\u0026lt;name\u0026gt;.ex สร้างไฟล์เทสของ module เราให้ด้วยที่ test/\u0026lt;name\u0026gt;_test.exs รวมถึงสร้าง README.md ให้เราด้วยอัตโนมัติเลย\u003c/p\u003e","title":"A day with Elixir"},{"content":"เกือบจะไม่ได้มาเขียนต่อกันละสำหรับ Part 2 ของ dataclass ตอนที่หนึ่งอยู่ที่ โพสนี้ นะครับ แต่เพื่อไม่ให้เป็นการเสียเวลาไปมากกว่านี้ เราไปต่อกันที่ Part 2 เลยครับ\nตอนที่แล้วเราได้รู้จัก dataclass ได้รู้ถึงเหตุผลว่าทำไมถึงเกิดมันขึ้นมา ตอนนี้เรามาจะมาโฟกัสกันว่า เราจะใช้ dataclass กับโค้ดเรายังไงครับ\nตัวอย่างการใช้งาน dataclass\nอย่างแรกที่เราเห็นเลยคือ เราไม่ต้องเขียน __init__ method กันอีกแล้วครับ ตัว dataclass จะ generate โค้ดส่วนนั้นให้ และอีกอย่างที่เราสังเกตุเห็นเลยคือ dataclass ใช้ประโยชน์จาก Type hint เต็มๆ อย่างที่เราเห็นการประกาศ Attribute ข้างต้นจะมีการประกาศ Type ประกบด้วยทุกตัว ทำให้เราสามารถเข้าใจ Attribute แต่ละตัวได้ทันทีว่าใช้ Type อะไรโดยไม่ต้องเดา\nอย่างที่สองครับ Representation ตัว dataclass เนี่ยนอกจากจะ generate __init__ ให้เราแล้วอีกตัวที่ทำให้คือ __repr__ ครับ ซึ่งตัว dataclass เนี่ยจะใช้ข้อมูลจาก attribute ที่เรา define ไว้มาสร้างให้ซึ่งช่วยเพิ่มความสะดวกให้เราและทำให้เราเลิกคิดไปได้หนึ่งเรื่อง หน้าตาก็จะประมาณนี้ครับ\nตัวอย่าง repr ที่ปริ้นต์ออกมาเมื่อใช้และไม่ใช้งาน dataclass\nรวมถึงถ้าเราจะดู Type ของแต่ละ Attribute ก็สามารถดูได้ผ่าน method __annotations__ ครับ\nตัวอย่างผลลัพธ์ที่ได้จาก method __annotations__\nถามว่ามีไว้ทำไม ลองคิดภาพว่าเราต้อง pdb เข้าไป debug แล้ว __repr__ ไม่ได้ implement หรือเราไม่รู้ type ของแต่ละ attribute ดูสิครับ เราต้องมานั่งเดาว่า Instance ไหนคือตัวไหน มีค่าอะไร หรือแต่ละค่าเป็น type อะไร แต่พอเรามี Method พวกนี้มาให้แล้ว เราไม่ต้องเดาแล้วครับ\nนอกจากสร้าง representation ให้แล้ว ตัว data class ยังสร้าง comparison method ให้ด้วยเช่น __lt__ , __le__ , __gt__ and __ge__ แต่ว่าเราต้องเพิ่ม argument order=True ใน decorator ของ dataclass ด้วยนะครับ มันถึงจะสร้าง method พวกนี้ให้\nตัวอย่างการเพิ่ม order ทำให้ dataclass compare ค่าใน instance ได้\nโดยมันจะอ่านค่าจาก attribute ของ instance เราแล้วเอามา compare กับ instance อื่นได้ทั้ง \u0026lt;, \u0026lt;=, \u0026gt;, \u0026gt;= ส่วน == นั้นทำได้อยู่แล้วครับจาก dataclass ไม่ต้องมาเปิดผ่าน order\nแต่ของที่ generate ขึ้นมารึจะสู้เราเขียนเอง ข้อเสียของ comparison method ที่มัน generate ให้คือมันไม่ฉลาดครับ ถ้าเราเอา class Team ที่เขียนข้างบนไปใช้ เราจะพบกับความประหลาด จนสงสัยว่ามันเทียบอะไร ยังไงของมัน นั่นทำให้เราต้องระบุค่าของแต่ละ attribute ผ่าน field() API ที่ dataclass สร้างมาให้ครับ\nfield() API นี่ สำหรับคนเคยใช้ ORM มาจะรู้สึกคุ้นหน้าคุ้นตามาก แต่ไม่เหมือนซะทีเดียว เพราะ field API นี่จะใช้ในการระบุ behavior ของ attribute ของ class แต่ละตัวว่าจะเอาไปใส่ใน representation รึเปล่า จะใช้ compare ด้วยมั้ย จะให้ attribute นี้เป็น immutable รึเปล่าหรือแม้กระทั่งใส่ metadata ไว้อธิบายว่า field นี้เอาไว้ทำอะไรก็ได้ครับ หน้าตาก็จะประมาณนี้\nตัวอย่างการใช้ field() API สำหรับกำหนดพฤติกรรมของ attribute\nเรื่อง immutable นี่ ถ้าเราอยากให้ทั้ง dataclass เราไม่สามารถแก้ไขข้อมูลได้เช่นเอาไว้เก็บ constant หรือ setting ต่างๆ เราสามารถระบุได้ใน decorator argument ว่า frozen=True ครับ อารมณ์เดียวกับ namedTuple เลย\nตัวอย่างการใช้ frozen ทำให้ dataclass เป็น immutable object\nเคสต่อมาคือ เราอยากให้หลังจากที่เรา instantiate dataclass แล้วอยากให้มันทำการคำนวนบางอย่าง ถ้าเป็นสมัยก่อนเราต้องสร้าง method ซักอย่างขึ้นมาใน class แล้วเรียกมันใน __init__ ใช่มั้ยครับ ในเคสของ dataclass เราสามารถกำหนดพฤติกรรมตรงนั้นได้ผ่าน method ที่ชื่อว่า __post_init__ ครับ\nตัวอย่างการใช้ __post_init__ กับ dataclass\nก็ประมาณนี้ครับ dataclass น่าจะครอบคลุมการใช้งานพื้นฐาน ถ้าอยากจะใช้งานลึกซึ้งมากกว่านี้เช่น Inheritance, __slot__ หรืออยากเข้าใจที่มาที่ไปมากกว่านี้ผมแนะนำ Talk ของ Raymond Hettinger ที่นี่เลยครับ\nหรือถ้าขี้เกียจฟังไปอ่าน Blog ที่ผมสรุปเนื้อหาที่เข้าใจได้ที่นี่ครับ\n#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators Key takeawaysSphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วยCode generator: tools that write code for you based on specificationdataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขี — Yothinix, Yothin Muangsommuk\nและเหมือนเดิมครับ ผมยังเชียร์ให้อ่าน Official Document ครับที่นี่\ndataclasses — Data Classes — Python 3.10.2 documentation — Logo\nOriginal post at: https://yothinix.medium.com/มารู้จัก-data-classes-กันครับ-4cb8e1eb5f6b\n","permalink":"https://yothinix-com.pages.dev/getting-start-with-dataclasses-in-python/","summary":"\u003cp\u003eเกือบจะไม่ได้มาเขียนต่อกันละสำหรับ Part 2 ของ dataclass ตอนที่หนึ่งอยู่ที่ \u003ca href=\"https://www.facebook.com/writepythontoscarecow/photos/a.206798910040303.1073741829.206323933421134/208169593236568/?type=3\u0026amp;theater\"\u003eโพสน\u003c/a\u003eี้ นะครับ แต่เพื่อไม่ให้เป็นการเสียเวลาไปมากกว่านี้ เราไปต่อกันที่ Part 2 เลยครับ\u003c/p\u003e\n\u003cp\u003eตอนที่แล้วเราได้รู้จัก dataclass ได้รู้ถึงเหตุผลว่าทำไมถึงเกิดมันขึ้นมา ตอนนี้เรามาจะมาโฟกัสกันว่า เราจะใช้ dataclass กับโค้ดเรายังไงครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp\"\n       srcset=\"/getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_62a9280381654e07.webp 480w, /getting-start-with-dataclasses-in-python/1-qsBciri74At9SXPxlHy0WQ_hu_8d04e01d13e2bb7a.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"479\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eตัวอย่างการใช้งาน dataclass\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eอย่างแรกที่เราเห็นเลยคือ เราไม่ต้องเขียน __init__ method กันอีกแล้วครับ ตัว dataclass จะ generate โค้ดส่วนนั้นให้ และอีกอย่างที่เราสังเกตุเห็นเลยคือ dataclass ใช้ประโยชน์จาก Type hint เต็มๆ อย่างที่เราเห็นการประกาศ Attribute ข้างต้นจะมีการประกาศ Type ประกบด้วยทุกตัว ทำให้เราสามารถเข้าใจ Attribute แต่ละตัวได้ทันทีว่าใช้ Type อะไรโดยไม่ต้องเดา\u003c/p\u003e\n\u003cp\u003eอย่างที่สองครับ Representation ตัว dataclass เนี่ยนอกจากจะ generate __init__ ให้เราแล้วอีกตัวที่ทำให้คือ __repr__ ครับ ซึ่งตัว dataclass เนี่ยจะใช้ข้อมูลจาก attribute ที่เรา define ไว้มาสร้างให้ซึ่งช่วยเพิ่มความสะดวกให้เราและทำให้เราเลิกคิดไปได้หนึ่งเรื่อง หน้าตาก็จะประมาณนี้ครับ\u003c/p\u003e","title":"มารู้จัก Data classes กันครับ"},{"content":" Talk ผมดูวนอยู่สองสามรอบ เพราะต้องการเก็บทุกเม็ดทุกหน่วยจริงๆ คือ ผมไม่เคยเจอ Talk ที่ดูแล้วตื่นตาตื่นใจขนาดนี้มานานมาก ตอนนี้ยกให้เป็น Talk อันดับหนึ่งในใจของ PyCon ปีนี้เลย\nผมคิดว่า Talk นี้จะไม่สรุป Key Takeaway เพราะอยากให้คนที่มารู้จัก Talk นี้จากผมได้รับสารเต็มๆ จาก Ned Batchelder โดยการดู Talk นี้ครับ แต่ถ้าไม่มีเวลาดูจริงๆ แนะนำให้ไปอ่าน เวอร์ชั่น Text ที่เจ้าตัวเองถอดเขียนไว้ เป็นบทความที่ผม Recommend เลยครับ ทำให้ผมกลับมาคิดเรื่อง Algorithmic Analysis หลังจากหลงลืมมันไปนานมาก ลิ้งข้างล่างนี้ครับ\nBig-O: How Code Slows as Data Grows Big-O notation can be intimidating, but it doesn’t have to be. A common-sense approach will give you a good working technique for analyzing the time complexity of your code. — Ned Batchelder, about\nปล.นอกจากจะกลับมาสนใจเรื่อง Algorithmic Analysis แล้ว ยังทำให้ผมมาสนใจ data structure ตัวนึงที่แทบไม่เคยใช้เลย นั่นก็คือ { } ครับ\nOriginal post at: https://yothinix.medium.com/100daysofpycon2018-day6-big-o-how-code-slows-as-data-grows-4f204c51263b\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day6-big-o-how-code-slows-as-data-grows/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/duvZ-2UK0fc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cp\u003eTalk ผมดูวนอยู่สองสามรอบ เพราะต้องการเก็บทุกเม็ดทุกหน่วยจริงๆ คือ ผมไม่เคยเจอ Talk ที่ดูแล้วตื่นตาตื่นใจขนาดนี้มานานมาก ตอนนี้ยกให้เป็น Talk อันดับหนึ่งในใจของ PyCon ปีนี้เลย\u003c/p\u003e\n\u003cp\u003eผมคิดว่า Talk นี้จะไม่สรุป Key Takeaway เพราะอยากให้คนที่มารู้จัก Talk นี้จากผมได้รับสารเต็มๆ จาก Ned Batchelder โดยการดู Talk นี้ครับ แต่ถ้าไม่มีเวลาดูจริงๆ แนะนำให้ไปอ่าน เวอร์ชั่น Text ที่เจ้าตัวเองถอดเขียนไว้ เป็นบทความที่ผม Recommend เลยครับ ทำให้ผมกลับมาคิดเรื่อง Algorithmic Analysis หลังจากหลงลืมมันไปนานมาก ลิ้งข้างล่างนี้ครับ\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://nedbatchelder.com/text/bigo.html\"\u003eBig-O: How Code Slows as Data Grows\u003c/a\u003e\nBig-O notation can be intimidating, but it doesn’t have to be. A common-sense approach will give you a good working technique for analyzing the time complexity of your code.\n— Ned Batchelder, about\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day6: Big-O: How Code Slows as Data Grows"},{"content":" Key takeaway คนที่เคย commit password ลง Git มีอยู่ 2 ประเภท ประเภทแรกคือเผลอพลาดจริงๆ อีกประเภทคือบอกว่า commit สิแต่ไม่เป็นไรเพราะ… ซึ่งเพราะนี่มีหลายคนที่บอกว่า เพราะมันเป็น private repo แต่เราไม่ควรมองอย่างงั้นเพราะว่า Private Repo มันไม่ได้ encrypt เพราะฉะนั้นคนที่อยู่ GitHub ก็ยังดูข้อมูลเราได้อยู่ รวมถึงถ้าวันนึงคนในทีมออกจากบริษัทไป คนๆ นั้นก็ยังมี password นั้นอยู่ อีกเหตุผลคือ ไม่เป็นไรเพราะ password เราใช้ใน internal service แนวคิดนี้มาจากการจำกัดบริเวณความเสียหาย ซึ่งก็ยังไม่ตอบโจทย์อยู่ดี วิธีการ (ไม่) แก้ password ที่เผลอ commit ไปคือ สร้าง commit ใหม่ที่จะลบ password ถ้าเราใช้ git เป็นประจำเราจะรู้ว่าเราสามารถดู history ได้ซึ่งวิธีนี้ก็ไม่ได้แก้ปัญหาอะไร อีกวิธีที่บางคนคิดว่าแก้ปัญหาคือ rebase commit แต่มันไม่ได้แก้ปัญหาถึงแม้ว่า history จะเปลี่ยนไป แต่ git เก็บทุกอย่างแล้ว commit นี้ยังอยู่ใน ref log แต่เป็น orphant อยู่จนกว่าจะโดน garbage collect ไป รวมถึงถ้าในเคสที่คนที่ลาออกไปก่อนที่เราจะ rebase สุดท้ายเค้ายังมี password อยู่ดี เพราะมันไม่ได้แก้ทุกเครื่อง วิธีแก้ที่ดีสุดคือ Revoke password ซะ นี่เป็นสิ่งแรกที่เราควรทำเมื่อรู้ตัวว่า password เราเผลอ commit ไปแล้ว สิ่งต่อมาที่ควรทำคือ เราควรจะเก็บ password / secret ไว้ใน environment variable ซึ่งวิธีการ access มันใน Python เราสามารถใช้ module os.environ ในการเรียกได้ โดย module นี้จะเก็บ environment variable ทั้งหมดที่ OS ป้อนให้ process เราในรูปแบบ Dictionary วิธีการเก็บ password ใน environment variable เราสามารถเก็บผ่าน .profile หรือ .bashrc สำหรับทุกโปรเจ็ค แต่ถ้าเป็นโปรเจ็คเดี่ยวๆ จะแนะนำ .env มากกว่า และสำคัญที่สุดคือ อย่าพิมพ์ password ใน shell เพราะ shell เก็บ history ทุกอย่างที่พิมพ์ และไฟล์ .env ก็อย่า commit ลง git แต่ให้เขียน .gitignore กันไว้จะดีที่สุด Python มี Package ชื่อ python-dotenv เอาไว้ใช้สำหรับ load environment variable โดยเฉพาะ ซึ่งแค่แปะฟังก์ชั่น load_dotenv() ก่อนจะใช้ค่าใน env ก็ใช้ได้แล้วสะดวกมาก ไม่ต้องมานั่ง export env เอง ก่อนรัน app ถ้า environment variable ยังไม่ปลอดภัยพอ เรายังมีตัวเลือกอีกมากเช่น Vault (Hashicorp) / Parameter Store (AWS) / Secret Object (K8S) / Vault (Ansible) ซึ่งพวกนี้นอกจากจะเก็บ secret ให้เราแล้วยัง encrypt ให้ด้วย DO and DON’T อย่าเขียน password / token ไว้ใน code จงเรียก Password / token จาก environment variable หรือ secret store จง Revoke ตัว secret เราที่เผลอเปิดเผยไปแล้ว อย่าใช้ service ที่ไม่มี option ในการ revoke access token อย่าใช้ password เดียวกันหลาย service อย่าใช้ credential เดียวกันทุก Users Original Post on: https://yothinix.medium.com/100daysofpycon2018-day5-oops-i-committed-my-password-to-github-300fd7704a34\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day5-oops-i-committed-my-password-to-github/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/2uaTPmNvH0I?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003ch1 id=\"key-takeaway\"\u003eKey takeaway\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eคนที่เคย commit password ลง Git มีอยู่ 2 ประเภท ประเภทแรกคือเผลอพลาดจริงๆ อีกประเภทคือบอกว่า commit สิแต่ไม่เป็นไรเพราะ… ซึ่งเพราะนี่มีหลายคนที่บอกว่า เพราะมันเป็น private repo แต่เราไม่ควรมองอย่างงั้นเพราะว่า Private Repo มันไม่ได้ encrypt เพราะฉะนั้นคนที่อยู่ GitHub ก็ยังดูข้อมูลเราได้อยู่ รวมถึงถ้าวันนึงคนในทีมออกจากบริษัทไป คนๆ นั้นก็ยังมี password นั้นอยู่ อีกเหตุผลคือ ไม่เป็นไรเพราะ password เราใช้ใน internal service แนวคิดนี้มาจากการจำกัดบริเวณความเสียหาย ซึ่งก็ยังไม่ตอบโจทย์อยู่ดี\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eวิธีการ (ไม่) แก้ password ที่เผลอ commit ไป\u003c/strong\u003eคือ สร้าง commit ใหม่ที่จะลบ password ถ้าเราใช้ git เป็นประจำเราจะรู้ว่าเราสามารถดู history ได้ซึ่งวิธีนี้ก็ไม่ได้แก้ปัญหาอะไร อีกวิธีที่บางคนคิดว่าแก้ปัญหาคือ rebase commit แต่มันไม่ได้แก้ปัญหาถึงแม้ว่า history จะเปลี่ยนไป แต่ git เก็บทุกอย่างแล้ว commit นี้ยังอยู่ใน ref log แต่เป็น orphant อยู่จนกว่าจะโดน garbage collect ไป รวมถึงถ้าในเคสที่คนที่ลาออกไปก่อนที่เราจะ rebase สุดท้ายเค้ายังมี password อยู่ดี เพราะมันไม่ได้แก้ทุกเครื่อง\u003c/li\u003e\n\u003cli\u003eวิธีแก้ที่ดีสุดคือ Revoke password ซะ นี่เป็นสิ่งแรกที่เราควรทำเมื่อรู้ตัวว่า password เราเผลอ commit ไปแล้ว สิ่งต่อมาที่ควรทำคือ เราควรจะเก็บ password / secret ไว้ใน environment variable ซึ่งวิธีการ access มันใน Python เราสามารถใช้ module os.environ ในการเรียกได้ โดย module นี้จะเก็บ environment variable ทั้งหมดที่ OS ป้อนให้ process เราในรูปแบบ Dictionary\u003c/li\u003e\n\u003cli\u003eวิธีการเก็บ password ใน environment variable เราสามารถเก็บผ่าน .profile หรือ .bashrc สำหรับทุกโปรเจ็ค แต่ถ้าเป็นโปรเจ็คเดี่ยวๆ จะแนะนำ .env มากกว่า และสำคัญที่สุดคือ \u003cstrong\u003eอย่าพิมพ์ password ใน shell\u003c/strong\u003e เพราะ shell เก็บ history ทุกอย่างที่พิมพ์ และไฟล์ .env ก็อย่า commit ลง git แต่ให้เขียน .gitignore กันไว้จะดีที่สุด\u003c/li\u003e\n\u003cli\u003ePython มี Package ชื่อ \u003ca href=\"https://pypi.org/project/python-dotenv/\"\u003epython-dotenv\u003c/a\u003e เอาไว้ใช้สำหรับ load environment variable โดยเฉพาะ ซึ่งแค่แปะฟังก์ชั่น load_dotenv() ก่อนจะใช้ค่าใน env ก็ใช้ได้แล้วสะดวกมาก ไม่ต้องมานั่ง export env เอง ก่อนรัน app\u003c/li\u003e\n\u003cli\u003eถ้า environment variable ยังไม่ปลอดภัยพอ เรายังมีตัวเลือกอีกมากเช่น Vault (Hashicorp) / Parameter Store (AWS) / Secret Object (K8S) / Vault (Ansible) ซึ่งพวกนี้นอกจากจะเก็บ secret ให้เราแล้วยัง encrypt ให้ด้วย\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"do-and-dont\"\u003eDO and DON’T\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eอย่าเขียน password / token ไว้ใน code\u003c/li\u003e\n\u003cli\u003eจงเรียก Password / token จาก environment variable หรือ secret store\u003c/li\u003e\n\u003cli\u003eจง Revoke ตัว secret เราที่เผลอเปิดเผยไปแล้ว\u003c/li\u003e\n\u003cli\u003eอย่าใช้ service ที่ไม่มี option ในการ revoke access token\u003c/li\u003e\n\u003cli\u003eอย่าใช้ password เดียวกันหลาย service\u003c/li\u003e\n\u003cli\u003eอย่าใช้ credential เดียวกันทุก Users\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cp\u003eOriginal Post on: \u003ca href=\"https://yothinix.medium.com/100daysofpycon2018-day5-oops-i-committed-my-password-to-github-300fd7704a34\"\u003ehttps://yothinix.medium.com/100daysofpycon2018-day5-oops-i-committed-my-password-to-github-300fd7704a34\u003c/a\u003e\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day5: Oops! I Committed My Password To GitHub!"},{"content":" จริงๆ ดูจบตั้งแต่เมื่อเช้าแล้ว แต่คิดหนักมากว่าจะสรุปดีมั้ย เพราะทุกอย่างที่อยู่ใน Talk นี้คือรู้อยู่แล้ว ใช้อยู่ทุกวันอยู่แล้วไง แต่หลังจากคิดไปคิดเลยขอวางตัวเองออกไป แล้วคิดว่าไม่รู้อะไรเลยแล้วลองสรุปดีกว่า\nKey takeaway\nTDD crash course: Test ➡ Design \u0026amp; Develop วิธีที่เค้าเปรียบเทียบค่อนข้างจะน่าสนใจทีเดียว เค้าบอกว่าสมัยเรียนเวลาอ่าน text book มันใหญ่มาก บทนึงก็ยาว แต่เกือบทุกเล่มท้ายบทจะมีแบบทดสอบว่าเราเข้าใจรึเปล่า เค้าลดเวลาในการทำความเข้าใจทั้งบทด้วยการ อ่านคำถามท้ายบทก่อน แล้วค่อยไปหาอ่านเนื้อหา วิธีนี้ทำให้เข้าใจเนื้อหาได้เร็วทันทีแล้วไม่ต้องเสียเวลาอ่านน้ำ ถ้าเปรียบกับการเขียนโปรแกรมก็คงไม่ต่างอะไรกับเราไม่ต้องหลงทุ่งเขียนไปเรื่อย แต่ตั้งคำถามกับตัวเองว่าเรากำลังแก้ปัญหาอะไร แล้วพยายามแก้ปัญหานั้น Pytest สามารถรันเทสเป็นซับเซตได้ทั้งระดับ Directory, module หรือแม้กระทั้ง test case หรือใช้ marker, expression กำหนดว่าจะรันเทสไหน รวมถึงเพิ่ม option ให้รันแล้ว exit เลยเมื่อเทส failed หรือ รันเทสที่ failed ล่าสุดก่อน ฯลฯ Visual Testing vs CLI ต้องบอกว่าบางคนไม่ถูกกับ CLI จริงๆ เค้าเลยพยายามหาทางให้ทีมรันเทสให้ได้ง่ายขึ้นเลยมาจบที่ใช้ PyCharm ให้เรียก Pytest อีกที ซึ่งนอกจากจะใช้ครอบ Pytest ให้รันง่ายขึ้นแล้ว (ผ่าน gutter) ยังสามารถ debug test/code ไปพร้อมๆ กับรันเทสผ่าน breakpoint และ debugger ที่ติดมากับ PyCharm ได้ด้วย เราสามารถเทสฟังก์ชั่นเดิมแต่ใช้ input set ต่างกันได้ผ่าน pytest.mark.parameterize วิธีนี้ทำให้โค้ดเทสสะอาดขึ้นมาก เพราะเรา define แค่ parameter ตัวเทสก็เขียนเหมือนเดิมอยู่แล้ว ถ้าอยากศึกษาเพิ่มเติมเกี่ยวกับ PyTest ผมแนะนำหนังสือ Python Testing with pytest ครับ คนเขียนก็คนเดียวกับที่พูด Talk นี่แหละครับ นอกจากหนังสือนี้ทำให้รู้จักใช้ความสามารถต่างๆ ของ PyTest มากขึ้นแล้ว หนังสือเล่มนี้ทำให้ผมหลงรัก namedTuple ซึ่งเป็น data structure ที่คนมองข้ามมากตัวนึงเลยครับ Python Testing with pytest Python Testing with pytest, 2nd Edition 2nd edition is now in Beta, and purchasable as an eBook. All 16 chapters, plus 2 appendices, are in the Beta, available as an eBook. Copy editing and indexing are complete. The physical book is the next step. Final version expected Feb 2022 (or March, maybe)… — Python Testing\nOriginal Post at: https://yothinix.medium.com/100daysofpycon2018-day4-visual-testing-with-pycharm-and-pytest-9bf9bd4d7963\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day4-visual-testing-with-pycharm-and-pytest/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/FjojZxDZscQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cp\u003eจริงๆ ดูจบตั้งแต่เมื่อเช้าแล้ว แต่คิดหนักมากว่าจะสรุปดีมั้ย เพราะทุกอย่างที่อยู่ใน Talk นี้คือรู้อยู่แล้ว ใช้อยู่ทุกวันอยู่แล้วไง แต่หลังจากคิดไปคิดเลยขอวางตัวเองออกไป แล้วคิดว่าไม่รู้อะไรเลยแล้วลองสรุปดีกว่า\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eKey takeaway\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eTDD crash course\u003c/em\u003e: Test ➡ Design \u0026amp; Develop วิธีที่เค้าเปรียบเทียบค่อนข้างจะน่าสนใจทีเดียว เค้าบอกว่าสมัยเรียนเวลาอ่าน text book มันใหญ่มาก บทนึงก็ยาว แต่เกือบทุกเล่มท้ายบทจะมีแบบทดสอบว่าเราเข้าใจรึเปล่า เค้าลดเวลาในการทำความเข้าใจทั้งบทด้วยการ อ่านคำถามท้ายบทก่อน แล้วค่อยไปหาอ่านเนื้อหา วิธีนี้ทำให้เข้าใจเนื้อหาได้เร็วทันทีแล้วไม่ต้องเสียเวลาอ่านน้ำ ถ้าเปรียบกับการเขียนโปรแกรมก็คงไม่ต่างอะไรกับเราไม่ต้องหลงทุ่งเขียนไปเรื่อย แต่ตั้งคำถามกับตัวเองว่าเรากำลังแก้ปัญหาอะไร แล้วพยายามแก้ปัญหานั้น\u003c/li\u003e\n\u003cli\u003ePytest สามารถรันเทสเป็นซับเซตได้ทั้งระดับ Directory, module หรือแม้กระทั้ง test case หรือใช้ marker, expression กำหนดว่าจะรันเทสไหน รวมถึงเพิ่ม option ให้รันแล้ว exit เลยเมื่อเทส failed หรือ รันเทสที่ failed ล่าสุดก่อน ฯลฯ\u003c/li\u003e\n\u003cli\u003eVisual Testing vs CLI ต้องบอกว่าบางคนไม่ถูกกับ CLI จริงๆ เค้าเลยพยายามหาทางให้ทีมรันเทสให้ได้ง่ายขึ้นเลยมาจบที่ใช้ PyCharm ให้เรียก Pytest อีกที ซึ่งนอกจากจะใช้ครอบ Pytest ให้รันง่ายขึ้นแล้ว (ผ่าน gutter) ยังสามารถ debug test/code ไปพร้อมๆ กับรันเทสผ่าน breakpoint และ debugger ที่ติดมากับ PyCharm ได้ด้วย\u003c/li\u003e\n\u003cli\u003eเราสามารถเทสฟังก์ชั่นเดิมแต่ใช้ input set ต่างกันได้ผ่าน pytest.mark.parameterize วิธีนี้ทำให้โค้ดเทสสะอาดขึ้นมาก เพราะเรา define แค่ parameter ตัวเทสก็เขียนเหมือนเดิมอยู่แล้ว\u003c/li\u003e\n\u003cli\u003eถ้าอยากศึกษาเพิ่มเติมเกี่ยวกับ PyTest ผมแนะนำหนังสือ Python Testing with pytest ครับ คนเขียนก็คนเดียวกับที่พูด Talk นี่แหละครับ นอกจากหนังสือนี้ทำให้รู้จักใช้ความสามารถต่างๆ ของ PyTest มากขึ้นแล้ว หนังสือเล่มนี้ทำให้ผมหลงรัก namedTuple ซึ่งเป็น data structure ที่คนมองข้ามมากตัวนึงเลยครับ\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://pythontest.com/pytest-book/\"\u003ePython Testing with pytest\u003c/a\u003e\nPython Testing with pytest, 2nd Edition 2nd edition is now in Beta, and purchasable as an eBook. All 16 chapters, plus 2 appendices, are in the Beta, available as an eBook. Copy editing and indexing are complete. The physical book is the next step. Final version expected Feb 2022 (or March, maybe)…\n— Python Testing\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day4: Visual Testing with PyCharm and pytest"},{"content":" Key takeaways Sphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วย Code generator: tools that write code for you based on specification dataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขียน class ประวัติศาสตร์แบบย่อๆ เริ่มต้นเรามี dict, tuple, hand-written class หลังจากนั้น namedTuple 🎉✨ ก็เกิดขึ้นแล้วตามมาด้วย types.SimpleNamespace ทำให้เราสร้าง data structure ได้ง่ายขึ้น (access ได้ง่ายขึ้นด้วย) ในอีกมุมนึง ORMs ก็กำเนิดขึ้นด้วยจาก Django, SQLAlchemy, PeeWee ซึ่งใช้ class เป็นเทคนิคในการสร้าง data structure หลังจากนั้นมี traitlets เกิดขึ้นเป็น package ไว้ใช้ทำ data validation โดยใช้ class attribute เป็นตัวกำหนด พอ Python 3.6 ออกก็เกิด Type Annotation, Variable Annotation ช่วยให้เราสามารถ define type ของ attribute ของ class ได้เลย ท้ายที่สุดเรามี library ชื่อ attrs เป็นแรงบันดาลใจในการสร้าง dataclass สามารถมองง่ายๆ ได้ว่าเป็น “Mutable namedtuples with defaults” Dataclass เบสิกเลยเขียนคล้าย namedTuple มาก ต่างกันแค่ dataclass ใช้ decorator dataclass แต่ NamedTuple ต้อง inheritance ออกมาจาก NamedTuple class ความสามารถของ Dataclass สร้าง repl ให้เราโดยอัตโนมัติจาก attribute definition เลย ใช้ replace() ในการ mutable attribute ได้ เช่น replace(c, hue=120) ถ้าเป็น namedTuple ต้องใช้ c._replace(hue=120) เพื่อป้องกัน namespace collision ใช้ asdict() หรือ astuple() ให้คืนค่าออกมาเป็น dict หรือ tuple ได้เลย ข้อสังเกตุของ asdict() คือ dataclass จะคืน Dict ออกมาให้เลยในขณะที่ namedTuple จะคืน OrderedDict เพราะเป็น implementation เก่า มี method __annotations__ เอาไว้ดู type annotation ของ attributes ได้ ข้อเสียของ dataclass คือ unpack ของได้ยากกว่า namedTuple (เพราะ implementation ข้างล่างสุดเป็น Dict) ทำให้ก่อน unpack ต้องแปลงเป็น tuple ก่อน ในเรื่องของ Performance / Resource ตัว dataclass จะมีขนาดใหญ่กว่า namedTuple แต่แลกมาด้วยความเร็วในการ access object ที่เร็วกว่า Dataclass สร้าง docstring, __repr__, __eq__ ให้เราโดยอัตโนมัติจาก attribute ที่เรา define ไว้แต่ไม่สร้าง __hash__ ให้นะ ถ้าเราใส่ option frozen = True ใน dataclass decorator จะเป็นการบอกว่า dataclass นี้เป็น immutable หรือถ้ามองง่ายๆ คือให้มันทำตัวเป็น namedTuple ใส่ option order = True ได้ด้วยแต่ผมฟังแล้วไม่ค่อยเข้าใจชัดเจนว่าตกลงมัน order ของอะไรกันแน่ Customize Fields Specification นอกจากจะกำหนดพฤติกรรมของ dataclass ได้จาก decorator แล้วเรายังสามารถใช้ฟังก์ชั่น field() ในการกำหนดพฤติกรรมของแต่ละ attribute ได้ด้วย ตัวอย่างข้างบนเป็น use case คล้ายๆ ของจริงที่ต้องการสร้าง data structure ของ employee ขึ้นมา แล้วเก็บข้อมูลต่างๆ ในนี้ใช้ความสามารถของ field() หลากหลายมาก\nเราสามารถสร้าง default_factory ได้ผ่าน option: default_factory ในเคสนี้เป็นการสร้าง list เปล่าให้กับ viewed_by เราสามารถสร้าง custom method ได้เหมือน class ปกติทั่วไป ในเคสนี้คือ เมธอด access() เราสามารถ exclude บาง field ออกจากการ hash ได้โดยกำหนด hash=False ในเคสนี้คือ salary กับ age จะไม่สามารถเปลี่ยนแปลงค่าได้หรือ immutable นั่นเอง เราสามารถ exclude field ให้มันแสดงใน repl ได้ใช้ repr=False ในเคสนี้คือเราไม่อยากแสดง salary เวลา print ออกมา เราสามารถ exclude field ไม่ให้ต้อง compare ได้มีประโยชน์เวลากัน attribute ที่เป็น complex number หรือ function ที่ไม่สามารถ order ได้ออกไป สามารถกำหนดได้โดยใช้ compare=False ข้อมูลบางอย่างอาจจะต้องมีคำอธิบายเช่น เงินเดือนเป็นหน่วยอะไร หรือ field นี้มีความหมายว่าอะไร เราสามารถใส่ข้อมูลพวกนี้ลงไปใน metadata ได้เหมือนเคส salary ข้างบน จริงๆ ในช่วงท้ายมีพูดถึง slots ด้วยแต่ผมฟังไม่ค่อยเข้าใจ รู้แค่ว่ามันจะ optimize ให้เรา access ของได้เร็วขึ้น กับเรื่อง __post_init__() ที่ไม่สามารถใช้ได้ อะไรประมาณนี้\nวันก่อนผมไปเจอ blog ของ RealPython เขียนเรื่อง dataclass ไว้พอดี อธิบายไว้ดีพอสมควรเลยครับ รวมถึงเรื่อง slots ด้วยสนใจก็ไปอ่านต่อกันได้\nData Classes in Python 3.7+ (Guide) – Real Python Data classes are one of the new features of Python 3.7. With data classes you do not have to write boilerplate code to get proper initialization, representation and comparisons for your objects. — Real Python, Real Python\nOriginal post at: https://yothinix.medium.com/100daysofpycon2018-day3-dataclasses-the-code-generator-to-end-all-code-generators-694b9db7530a\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day3-dataclasses-the-code-generator-to-end-all-code-generators/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/T-TwcmT6Rcw?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003ch1 id=\"key-takeaways\"\u003eKey takeaways\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eSphinx ก็เอามาใช้ทำ Presentation ได้ แถมได้ document ที่อ่านง่ายกลับไปดูทีหลังได้ด้วย\u003c/li\u003e\n\u003cli\u003eCode generator: tools that write code for you based on specification\u003c/li\u003e\n\u003cli\u003edataclasses มี learning curve ต่ำมาก ถ้ามองสามารถมองได้สองมุมคือ data holder เหมือน namedTuple หรือเป็น boilerplate เอาไว้เขียน class\u003c/li\u003e\n\u003cli\u003eประวัติศาสตร์แบบย่อๆ เริ่มต้นเรามี dict, tuple, hand-written class หลังจากนั้น namedTuple 🎉✨ ก็เกิดขึ้นแล้วตามมาด้วย types.SimpleNamespace ทำให้เราสร้าง data structure ได้ง่ายขึ้น (access ได้ง่ายขึ้นด้วย) ในอีกมุมนึง ORMs ก็กำเนิดขึ้นด้วยจาก Django, SQLAlchemy, PeeWee ซึ่งใช้ class เป็นเทคนิคในการสร้าง data structure หลังจากนั้นมี traitlets เกิดขึ้นเป็น package ไว้ใช้ทำ data validation โดยใช้ class attribute เป็นตัวกำหนด พอ Python 3.6 ออกก็เกิด Type Annotation, Variable Annotation ช่วยให้เราสามารถ define type ของ attribute ของ class ได้เลย ท้ายที่สุดเรามี library ชื่อ attrs เป็นแรงบันดาลใจในการสร้าง dataclass\u003c/li\u003e\n\u003cli\u003eสามารถมองง่ายๆ ได้ว่าเป็น “Mutable namedtuples with defaults”\u003c/li\u003e\n\u003cli\u003eDataclass เบสิกเลยเขียนคล้าย namedTuple มาก ต่างกันแค่ dataclass ใช้ decorator \u003cstrong\u003edataclass\u003c/strong\u003e แต่ NamedTuple ต้อง inheritance ออกมาจาก \u003cstrong\u003eNamedTuple\u003c/strong\u003e class\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"ความสามารถของ-dataclass\"\u003eความสามารถของ Dataclass\u003c/h1\u003e\n\u003cscript src=\"https://gist.github.com/yothinix/2a6f01c52ea1331202b782dd3a0b3391.js\"\u003e\u003c/script\u003e\n\u003cul\u003e\n\u003cli\u003eสร้าง repl ให้เราโดยอัตโนมัติจาก attribute definition เลย\u003c/li\u003e\n\u003cli\u003eใช้ replace() ในการ mutable attribute ได้ เช่น replace(c, hue=120) ถ้าเป็น namedTuple ต้องใช้ c._replace(hue=120) เพื่อป้องกัน namespace collision\u003c/li\u003e\n\u003cli\u003eใช้ \u003cstrong\u003easdict()\u003c/strong\u003e หรือ \u003cstrong\u003eastuple()\u003c/strong\u003e ให้คืนค่าออกมาเป็น dict หรือ tuple ได้เลย ข้อสังเกตุของ asdict() คือ dataclass จะคืน Dict ออกมาให้เลยในขณะที่ namedTuple จะคืน OrderedDict เพราะเป็น implementation เก่า\u003c/li\u003e\n\u003cli\u003eมี method __annotations__ เอาไว้ดู type annotation ของ attributes ได้\u003c/li\u003e\n\u003cli\u003eข้อเสียของ dataclass คือ unpack ของได้ยากกว่า namedTuple (เพราะ implementation ข้างล่างสุดเป็น Dict) ทำให้ก่อน unpack ต้องแปลงเป็น tuple ก่อน\u003c/li\u003e\n\u003cli\u003eในเรื่องของ Performance / Resource ตัว dataclass จะมีขนาดใหญ่กว่า namedTuple แต่แลกมาด้วยความเร็วในการ access object ที่เร็วกว่า\u003c/li\u003e\n\u003cli\u003eDataclass สร้าง \u003cstrong\u003edocstring\u003c/strong\u003e, \u003cstrong\u003e__repr__\u003c/strong\u003e, \u003cstrong\u003e__eq__\u003c/strong\u003e ให้เราโดยอัตโนมัติจาก attribute ที่เรา define ไว้แต่ไม่สร้าง \u003cstrong\u003e__hash__\u003c/strong\u003e ให้นะ\u003c/li\u003e\n\u003cli\u003eถ้าเราใส่ option \u003cstrong\u003efrozen =\u003c/strong\u003e True ใน dataclass decorator จะเป็นการบอกว่า dataclass นี้เป็น immutable หรือถ้ามองง่ายๆ คือให้มันทำตัวเป็น namedTuple\u003c/li\u003e\n\u003cli\u003eใส่ option order = True ได้ด้วยแต่ผมฟังแล้วไม่ค่อยเข้าใจชัดเจนว่าตกลงมัน order ของอะไรกันแน่\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1 id=\"customize-fields-specification\"\u003eCustomize Fields Specification\u003c/h1\u003e\n\u003cp\u003eนอกจากจะกำหนดพฤติกรรมของ dataclass ได้จาก decorator แล้วเรายังสามารถใช้ฟังก์ชั่น field() ในการกำหนดพฤติกรรมของแต่ละ attribute ได้ด้วย ตัวอย่างข้างบนเป็น use case คล้ายๆ ของจริงที่ต้องการสร้าง data structure ของ employee ขึ้นมา แล้วเก็บข้อมูลต่างๆ ในนี้ใช้ความสามารถของ field() หลากหลายมาก\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day3: Dataclasses: The code generator to end all code generators"},{"content":" Key takeaway:\n— กว่าจะมาเป็น pip ที่เราใช้กันทุกวันนี้ก็ผ่านอะไรมาเยอะมากตั้งแต่ยุค build tarball มายุค easy_install มาถึงยุค pip + virtualenv มันยาวนานมาก เพิ่งรู้ว่า easy_install ไม่มี easy uninstall แล้วสมัยนั้นมันลบกันยังไง\n— ข้อเสียของยุค pip + requirements.txt คือเราลง package เดียวกันคนละ version ไม่ได้ (Ruby ทำได้) แล้ววิธีที่แนะนำคือ pip freeze \u0026gt; requirements.txt ก็มีปัญหาคือมาดูทีหลังจะงงว่า อันไหนคือ package ที่เราต้องการจริงๆ และ pip-tools พยายามแก้ปัญหานี้แล้วโดยใช้ requirements.in กับ requirements.txt แต่มันก็ยังหลายไฟล์อยู่\n— Virtualenv ปัญหาใหญ่สุดคือเข้าใจยากมากสำหรับคนที่เพิ่งใช้ เพราะ concept นี้ใกล้เคียงกับ unix ที่แยก home environment แต่ก้มีคนทำ virtualenv-wrapper (เกิดทันเว้ย) มาแก้ปัญหาในจุดนี้\n— Pipfile ทำให้เราแยก group ของ package ที่ลงได้ packages กับ dev packages\n— Pipenv ทำให้เราทำงานกับ Pipfile, Pipfile.lock และ virtualenv ได้ง่ายขึ้นโดยไม่ต้องแก้มันตรงๆ ทุกอย่างอยู่ใน interface เดียว แถมรับรอง deterministic build ของ package ด้วย (ผ่าน Pipfile.lock)\n— เพิ่งรู้ว่าถ้าสั่ง pipenv python \u0026lt;version\u0026gt; แล้วถ้า version นั้นไม่มี ถ้าเรามี pyenv มันจะลง version นั้นให้เลย\n— pipenv install — deploy เอาไว้ลงใน production\n— pipenv check เพิ่งเคยเห็นมันเตือนจริงๆ เอาไว้เช็คว่า package เรามี security flaw รึเปล่า (ผ่าน PyUP)\n— ถ้าเรามี directory .venv อยู่ใน project folder แล้ว pipenv จะลง virtualenv ให้ในนั้นเลย\nOriginal post at: https://yothinix.medium.com/100daysofpycon2018-day1-pipenv-the-future-of-python-dependency-management-508ab54769da\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day1-pipenv-the-future-of-python-dependency-management/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/GBQAKldqgZs?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cp\u003e\u003cstrong\u003eKey takeaway:\u003c/strong\u003e\u003cbr\u003e\n— กว่าจะมาเป็น pip ที่เราใช้กันทุกวันนี้ก็ผ่านอะไรมาเยอะมากตั้งแต่ยุค build tarball มายุค easy_install มาถึงยุค pip + virtualenv มันยาวนานมาก เพิ่งรู้ว่า easy_install ไม่มี easy uninstall แล้วสมัยนั้นมันลบกันยังไง\u003c/p\u003e\n\u003cp\u003e— ข้อเสียของยุค pip + requirements.txt คือเราลง package เดียวกันคนละ version ไม่ได้ (Ruby ทำได้) แล้ววิธีที่แนะนำคือ pip freeze \u0026gt; requirements.txt ก็มีปัญหาคือมาดูทีหลังจะงงว่า อันไหนคือ package ที่เราต้องการจริงๆ และ pip-tools พยายามแก้ปัญหานี้แล้วโดยใช้ requirements.in กับ requirements.txt แต่มันก็ยังหลายไฟล์อยู่\u003c/p\u003e\n\u003cp\u003e— Virtualenv ปัญหาใหญ่สุดคือเข้าใจยากมากสำหรับคนที่เพิ่งใช้ เพราะ concept นี้ใกล้เคียงกับ unix ที่แยก home environment แต่ก้มีคนทำ virtualenv-wrapper (เกิดทันเว้ย) มาแก้ปัญหาในจุดนี้\u003c/p\u003e\n\u003cp\u003e— Pipfile ทำให้เราแยก group ของ package ที่ลงได้ packages กับ dev packages\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day1: Pipenv: The Future of Python Dependency Management"},{"content":" Key takeaways\n— Garbage collector (GC) จะทำงานอยู่บนหลักการสองอย่างคือ Reference count กับ Copy-On-Write Semantic\n- Instagram disable GC ช่วยลด memory ได้จาก 500mb / process เหลือ 350mb / process (ลองคิดภาพ uWSGI ลดได้ขนาดนั้นแล้วรันซัก 100 กว่า process)\n- ใช้ perf ในการทำ profiling memory usage\n- Disable โดยใช้คำสั่ง gc.disable() ไม่เกิดอะไรขึ้น แต่ใช้ gc.set_threshold(0) ปิดได้จริงแต่สิ่งที่เกิดขึ้นคือ Instagram down เพราะ OOM ต้องแก้โดย hack atexit.register(os._exit, 0) แต่ปัจจุบันไม่ต้องแก้แล้วเพราะ hack นี้รวมไปใน Python 3.6 แล้ว\n- หลังจากปิด GC ไป Memory utilize ลดลง 15% มี shared memory เพิ่มขึ้น 100mb และ instruction / cycle เพิ่มขึ้น 10%\n- หลังจากปิดไปได้ซักพักเริ่มมีปัญหาเพราะ cyclic reference ป้องกันได้ยากมากในทีมที่โค้ดและขนาดทีมโตเร็วมากๆ อย่าง Instagram ทำให้ถึงแม้ว่าจะลด memory utilize ไปได้ แต่ขนาด process กลับโตขึ้นแทนจาก 600mb เป็น 1200mb ในปีเดียว\n- ทีม Instagram เริ่มมองที่ GC COW ว่าจะทำยังไงให้มันมีประสิทธิภาพมากขึ้นถ้าเปิด GC เลยจบลงด้วยการออกแบบ PYGC_HEAD ใหม่ โดยย้ายเอามาเก็บใน memory pool แล้วใช้ poiter reference หา memory page อื่น แต่ก็ต้องเสีย 16kb เอาไว้ทำ pointer ต่อ object\n- แทนที่จะย้าย PYGC_HEAD เอามาเก็บในใน memory page อันใหม่แล้วเสีย 16kb ทีม Instgram เลือกที่จะใช้ gc.freeze() ตัว memory page ก่อนที่จะ fork ไปสร้าง memory page ให้ object ใหม่\nWrap up\n— disable garbage collection to avoid copy-on-write\n— re-enable garbage collection by freezing objects\n— no GC before fork to avoid copy on write reallocation from memory pool\nหนักหน่วงมาก session นี้มี blog ด้วย ไปอ่านต่อกันได้\nCopy-on-write friendly Python garbage collection At Instagram, we have the world’s largest deployment of the Django web framework, which is written entirely in Python. We began using… — Instagram Engineering, Instagram Engineering\nOriginal post at: https://yothinix.medium.com/100daysofpycon2018-day2-there-and-back-again-disable-and-re-enable-garbage-collector-at-136b6103bfb4\n","permalink":"https://yothinix-com.pages.dev/100daysofpycon2018-day2-there-and-back-again-disable-and-re-enable-garbage-collector/","summary":"\u003ciframe width=\"200\" height=\"113\" src=\"https://www.youtube.com/embed/WVnACT48CkE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003cp\u003e\u003cstrong\u003eKey takeaways\u003c/strong\u003e\u003cbr\u003e\n— Garbage collector (GC) จะทำงานอยู่บนหลักการสองอย่างคือ Reference count กับ Copy-On-Write Semantic\u003c/p\u003e\n\u003cp\u003e- Instagram disable GC ช่วยลด memory ได้จาก 500mb / process เหลือ 350mb / process (ลองคิดภาพ uWSGI ลดได้ขนาดนั้นแล้วรันซัก 100 กว่า process)\u003c/p\u003e\n\u003cp\u003e- ใช้ perf ในการทำ profiling memory usage\u003c/p\u003e\n\u003cp\u003e- Disable โดยใช้คำสั่ง gc.disable() ไม่เกิดอะไรขึ้น แต่ใช้ gc.set_threshold(0) ปิดได้จริงแต่สิ่งที่เกิดขึ้นคือ Instagram down เพราะ OOM ต้องแก้โดย hack atexit.register(os._exit, 0) แต่ปัจจุบันไม่ต้องแก้แล้วเพราะ hack นี้รวมไปใน Python 3.6 แล้ว\u003c/p\u003e\n\u003cp\u003e- หลังจากปิด GC ไป Memory utilize ลดลง 15% มี shared memory เพิ่มขึ้น 100mb และ instruction / cycle เพิ่มขึ้น 10%\u003c/p\u003e","title":"#100DaysOfPyCon2018 Day2: There and Back Again: Disable and re-enable garbage collector at Instagram"},{"content":"มันมีสิ่งหนึ่งที่ผมสงสัยมานานหลายปีละว่าทำไมหลายคนถึงติดสมุด Moleskine มากๆ ทั้งๆ ที่มันก็ดูเหมือนสมุดธรรมดาๆ เล่มนึง ที่อาจจะมีเส้น ไม่มีเส้น เป็นตาราง ฯลฯ หลังจากถามไถ่หลายคนก็ยังไม่เคลียร์เพื่อคลายความสงสัยนั้น ผมเลยซื้อมาหนึ่งเล่มครับแล้วหลังจาก 3 เดือนที่ผ่านมา ผมค้นพบว่ามันก็สมุดธรรมดาๆ นี่แหละ แต่สิ่งที่ไม่ธรรมดามันเกิดขึ้นหลังจากนั้นครับ\nตั้งแต่สมัยเรียนแล้ว ผมไม่ใช่คนประเภทใช้สมุดครับ ตั้งแต่ปี 2 แล้วผมได้ Thinkpad Edge 11 มาผมก็อยู่บน Evernote มาตลอด อาจจะเปลี่ยนไปใช้ OneNote ตอนอยู่ปีสี่บ้าง จนมาถึงทำงานที่ใช้ Bear หรือไม่ก็สร้างไฟล์จดลง git repo ตัวเองผมไม่เคยคิดจะกลับไปใช้สมุดเลยครับ ทุกอย่างจะสามารถ Search หาได้มี hashtag / group อะไรเก็บไว้อย่างเป็นระบบ หลายตัวเขียน Markdown ได้หรือมี Format ที่ทำให้เขียนแล้วดูดีขึ้นไปอีก\nจริงๆ ก็ยังใช้ Bear อยู่นะ\nซึ่งจดอย่างนี้มันก็ไม่มีปัญหาอะไรนะครับ ไม่ได้จะบอกว่าเห้ยจดแบบนี้มันไม่ดีนะ แต่คือผมอยากลองอะไรใหม่ๆ ไง\nนอกจากเรื่องจดอีกเรื่องนึงคือ Todo list ครับ หลายต่อหลายปีมากที่ผมพยายามจะอยู่กับ App todo list แต่สุดท้ายแล้วอยู่กับ App ไม่รอดถึงมันจะ Sync หลาย Platform มีฟีเจอร์เตือน นั่นนู่นนี่ก็เหอะ ไม่รอดครับ เพิ่งรู้ตัวว่า Todolist ที่รอดสำหรับผมคือ ใช้แล้วทิ้ง นั่นก็คือ เขียนลง Post-it เวิร์คสุด\nกลับมาต่อหลังจากได้สมุด ผมคิดหนักมากครับว่าจะจดไรดีวะ มีตั้งร้อยกว่าหน้าจะใช้ยังไงหมด ที่เคยได้ยินมาก็รู้จักแค่ Cornell method ที่แบ่งๆ ช่องในหน้าเวลาจด แต่คือก็ไม่ได้ประชุมบ่อยขนาดนั้นไง\nThe Best Techniques for Taking Notes We don’t stop taking notes after we graduate: it’s something many of us do in some capacity throughout our adult lives, too. It may not even be something you really think about—you just do it. But you could probably also do it better, and that’s where we come in. It may be time to get back to the ba… — Lifehacker, The A.V. Club\nระหว่างที่นั่นงงงวยกับตัวเอง ผมก็เปิดไปเจอเว็บ http://bulletjournal.com/ ทำให้ผมรู้จักว่า เห้ย มันมีคนคิดระบบที่ทำให้เราใช้สมุดด้วยหวะ (คือเอาจริงๆ ก็เคยเห็นพวกสมุด Yearly Planner อะไรพวกนี้นะ แต่ไม่เคยคิดจะใช้เลย เพราะว่ามันรู้สึกบังคับเกินไป)\nรู้จัก Bullet Journal (BuJo) Bullet Journal ถูกคิดค้นโดยพ่อหนุ่มนามว่า Ryder Carroll และไม่ใช่ปุปปับจะคิดได้มาขนาดนี้นะ แต่ System นี้ถูกคิดและลองผิดลองถูกมาหลายปีกว่าจะเกิดมาเป็น BuJo อย่างที่เราเห็นในปัจจุบัน สมุดพวก Yearly Planner หรือ Journal อย่างที่ผมบอกครับ ส่วนใหญ่มันจะตีเส้น ตาราง​ ฯลฯ อะไรมาให้เป็น Structure แล้วซึ่งมันซับซ้อนเกินไปและใช้เวลากับความคิดเยอะกว่าจะจดได้ มันเลยเกิดเทคนิคที่เรียกว่า Rapid Logging ขึ้นมาครับซึ่งประกอบด้วยส่วนประกอบหลัก 4 อย่างคือ Topics, Page number, Short sentences และ Bullets ครับ\nTopics ก็ตรงตัวครับ ก่อนจะเขียนอะไรก็ต้องมีหัวข้อก่อน เอาที่เข้าใจง่าย อ่านรอบเดียวเข้าใจเลยว่าที่เหลือคือเรื่องอะไร Page Number อันนี้สำคัญมากครับและผมเพิ่งมาเข้าใจตอนที่คุยกับคนอื่นเวลาบอกว่าไม่ชอบใช้สมุดเพราะหาไม่เจอ สิ่งนี้แหละครับคือตัวแก้ปัญหา ใส่เลขหน้าให้มันซะ แล้วทำสารบัญ แค่นี้ก็หาเจอแล้วครับ Short Sentences ประโยคสั้นๆ ก็ประโยคสั้นๆ ครับอาจจะเป็นงานที่ต้องทำ,​ นัดหมาย บันทึกช่วยจำ เป็นอะไรก็ได้ครับ ขอแค่สั้นๆ พอ Bullets สิ่งนี้คือพระเอกของเราเลยครับ เวลาเราจดอะไรปกติเราจะมีขีดหรือจุดเอาไว้แยกประโยคใช่มั้ยครับ แต่ใน System นี้จุดนี้มีหลายแบบ หลายความหมายครับ ซึ่งอันนี้แล้วแต่คนจะ define เลย แต่ก็จะมีแนวทางหลักๆ ที่คน ใช้กันเยอะอย่างเช่น\n· อันนี้ผมจะแทนงานที่ต้องทำหรือ Todo\nX อันนี้คืองานที่ทำเสร็จแล้ว ปกติคือเขียนทับตัวข้างบน\n\u0026gt; อันนี้เป็นงานที่ไม่เสร็จแล้วต้องย้ายไปวันอื่น\n- อันนี้เป็นโน๊ตครับ\n° จริงๆ อยากจะเขียนว่าจุดที่มันกลวง อันนี้คือ Event ครับ Photo by Bich Tran from Pexels https://www.pexels.com/photo/bullet-journal-key-732439/\nนอกจาก Rapid Logging แล้ว System นี้ยังมีส่วนประกอบอีกอย่างเราเรียกมันว่า Module ครับ ซึ่งอันนี้ค่อนข้างจะเหมือนๆ กันทุกคนถ้าใช้ BuJo โดยจะประกอบด้วย 3 ส่วนๆ หลักๆ คือ\nIndex หรือสารบัญนั่นแหละครับใช้ประกอบกับ Page Number ที่ผมพูดถึงข้างบนสิ่งนี้จะช่วยให้เราหาของที่อยู่ในเล่มได้ง่ายโคตรๆ เหมือนเรากำลังเขียนหนังสือเล่มนึงเลย Future Log อันนี้เอาไว้ใส่อะไรก็ตามที่ต้องทำที่ต้องวางแผนล่วงหน้าหลักเดือน แต่ส่วนใหญ่แล้วคนจะนิยมเขียน Future Log อยู่ในหน้าเดียวกัน (ที่เป็นสองหน้า) แล้วแบ่งช่องไว้ 6 ช่องสำหรับ 6 เดือนครับ ซึ่งรูปแบบไม่มีตายตัวครับ บางคนอาจจะแบ่งช่องไว้เฉยๆ แล้วเขียนเดือนกำกับ แต่สำหรับผมผมเขียนปฏิทินไว้เลยครับ 1/4 ของหน้าแล้วแบ่งที่เหลือเอาไว้เขียน bullet มันทำให้ผมมองภาพรวมออกว่าว่างช่วงไหนบ้างด้วย เวลาใส่ก็วงวันที่ในเดือนไปด้วย Monthly Log หลักการเดียวกับ Future Log ครับ อันนี้เอาไว้ใส่อะไรที่จะเกิดขึ้นในเดือน ปกติแล้ว Title จะเป็นชื่อเดือนแล้วจะเขียนวันที่เรียงลงมาในหน้านั้นๆ ซึ่งส่วนตัวผมเองก็จะเขียนเต็มสองหน้าเหมือน Future Log ครับแต่จะแบ่งทางซ้ายเป็นวัน แล้วทางขวาจะเป็น Monthly Goal มันทำให้เห็นภาพรวมว่าเดือนนี้ต้องทำอะไรบ้างเร็วมาก Daily Log นอกจากจะซอยย่อยมาระดับเดือนแล้ว ยังซอยย่อยมาระดับวันอีกครับ คือเขียนวันที่ไปเลยว่าวันอะไรเป็นหัวข้อ แล้วข้างในก็ใส่อะไรลงไปเลยครับ ในส่วนนี้ผมลองมาทั้งแบบ เขียนวันต่อวัน กับตีตารางแบ่งสองหน้าเป็น Weekly Log เลยครับ ค้นพบว่าแบบที่ตีตารางแบ่งวันเป็น Weekly Log จะมีความรู้สึกอยากเขียนมากกว่า ไม่รู้ทำไมเหมือนกัน จดอย่างอื่นลงไปได้มั้ย? ที่ผมไล่ตามระบบทั้งหมดมาข้างบนเป็นแนวทางครับ เราอยากจะเพิ่มจะลดอะไรก็เรื่องของเราเลย ซึ่งนี่แหละเป็นสิ่งที่ทำให้ผมชอบมันมากๆ เพราะเราจะทำอะไรก็เรื่องของเรา ทีนี้คำถามคือเราจะเพิ่มอะไร ไอเดียมีเยอะมากครับอย่างส่วนตัวผมเองมี Mood Tracker มี จดบัญชีที่ลงทุนไว้บ้าง ฯลฯ ไม่มีกฏตายตัวครับ สมุดคือเอาไว้จด อยากจดอะไรก็จด แต่อย่าลืมทำ Index ก็พอครับ ไม่งั้นเดี๋ยวหาไม่เจอ\nนอกจาก Index แล้วผมค้นพบว่ามันจะมีบางอย่างที่ทำให้เราหาของได้ง่ายๆ เช่นแปะ Post It อันเล็กๆ ที่เป็น Label ไว้ให้มันโผล่ออกมาบ้างของส่วนสำคัญๆ เช่นๆ Index / Future Log / Monthly Log จะได้เปิดได้เร็วกว่าต้องไปไล่หาใน Index อีก\nLabel สำหรับส่วนสำคัญๆ ครับ อันนี้เล่มผมเอง\nสิ่งสำคัญที่สุด จะจดให้สนุก สิ่งสำคัญคือหาแรงบันดาลใจครับ ลองดูคนอื่นว่าเค้าทำยังไง ผมได้ไอเดียดีๆ หลายอย่างมากมาจากการดูคนอื่นยกตัวอย่างเช่น Page Number ผมไปเห็นคนนึงเค้าเขียนเฉพาะเลขคู่ ซึ่งเป็นวิธีที่ฉลาดโคตรๆ ทำให้เราไม่ต้องเขียนทุกหน้าแล้วเราเปิดดูแบบแง้มๆ ได้เลย หรืออย่าง Label ข้างบนนี่ผมก็เห็นคนอื่นทำมาอีกทีครับ แม้กระทั่ง Mood Tracker นี่ผมก็ไปดูคนอื่นทำแล้วมันน่าสนใจดีเลยลองทำเองมั่ง\nถ้าสนใจในเว็บไซต์ของ bulletjournal เองมี newsletter ให้เราอัพเดทเทคนิคใหม่ๆ ตลอดครับ หรือถ้าอยากอ่านเองตัวเว็บไซต์ก็มี Blog ที่จะมี Show Case ของแต่ละคนเรื่อยๆ เช่นกัน\nนอกจากเว็บไซต์หลักเองแล้วผมดูในไอจีครับตามแท๊ก #bujo กับ #bulletjournal เลยครับ จะได้ไอเดียใหม่ๆ กับได้เห็นคนจดสวยๆ เยอะมาก\nhttps://www.instagram.com/explore/tags/bujo/\nหรือใน Youtube ลอง Search ว่า bullet journal ก็จะเจอคนทำคลิปในการ Setup สมุดไว้เยอะมากเลยครับ ส่วนตัวผมชอบ Channel ของ AmandaRachLee เพราะเค้าทำเรื่องนี้เป็นหลักเลย\nAmandaRachLee Making my way through life with a pencil in hand and creativity in mind. Subscribe for new videos every week! Instagram: http://instagram.com/amandarachlee Twitter: https://twitter.com/amandarachlee Facebook: https://www.facebook.com/amandarachlee/ TikTok: @amandarachlee Website: https://www.amanda… — YouTube\nหมดแล้วครับ อยากบอกว่าลองจดดูซักอาทิตย์ แล้วคุณอาจจะเลิกใช้ Todo app, calendar app ไปเลยขอให้สนุกกับการจดครับผม\nปล.สุดท้ายมันไม่ได้เกี่ยวกับสมุด Moleskine เลยครับ แต่เป็นเรื่องระหว่างทางที่ทำให้ผมไปเจอ BuJo นี่แหละ\nOriginal post on: https://yothinix.medium.com/แนะนำ-bujo-เมื่อชีวิตอยากติด-analog-6c0ac0c2c22\n","permalink":"https://yothinix-com.pages.dev/bujo/","summary":"\u003cp\u003eมันมีสิ่งหนึ่งที่ผมสงสัยมานานหลายปีละว่าทำไมหลายคนถึงติดสมุด Moleskine มากๆ ทั้งๆ ที่มันก็ดูเหมือนสมุดธรรมดาๆ เล่มนึง ที่อาจจะมีเส้น ไม่มีเส้น เป็นตาราง ฯลฯ หลังจากถามไถ่หลายคนก็ยังไม่เคลียร์เพื่อคลายความสงสัยนั้น ผมเลยซื้อมาหนึ่งเล่มครับแล้วหลังจาก 3 เดือนที่ผ่านมา ผมค้นพบว่ามันก็สมุดธรรมดาๆ นี่แหละ แต่สิ่งที่ไม่ธรรมดามันเกิดขึ้นหลังจากนั้นครับ\u003c/p\u003e\n\u003cp\u003eตั้งแต่สมัยเรียนแล้ว ผมไม่ใช่คนประเภทใช้สมุดครับ ตั้งแต่ปี 2 แล้วผมได้ \u003cem\u003eThinkpad Edge 11\u003c/em\u003e มาผมก็อยู่บน \u003ca href=\"https://evernote.com/\"\u003eEvernote\u003c/a\u003e มาตลอด อาจจะเปลี่ยนไปใช้ \u003ca href=\"https://www.onenote.com/?public=1\u0026amp;wdorigin=ondcauth2\u0026amp;wdorigin=ondc\"\u003eOneNote\u003c/a\u003e ตอนอยู่ปีสี่บ้าง จนมาถึงทำงานที่ใช้ \u003ca href=\"http://www.bear-writer.com/\"\u003eBear\u003c/a\u003e หรือไม่ก็สร้างไฟล์จดลง git repo ตัวเองผมไม่เคยคิดจะกลับไปใช้สมุดเลยครับ ทุกอย่างจะสามารถ Search หาได้มี hashtag / group อะไรเก็บไว้อย่างเป็นระบบ หลายตัวเขียน Markdown ได้หรือมี Format ที่ทำให้เขียนแล้วดูดีขึ้นไปอีก\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/bujo/1-9lA2yuLIwaOIsz2g5N56Lw_hu_1939c5cfab3aba41.webp\"\n       srcset=\"/bujo/1-9lA2yuLIwaOIsz2g5N56Lw_hu_c4f00e57d878f743.webp 480w, /bujo/1-9lA2yuLIwaOIsz2g5N56Lw_hu_1939c5cfab3aba41.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"600\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eจริงๆ ก็ยังใช้ Bear อยู่นะ\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eซึ่งจดอย่างนี้มันก็ไม่มีปัญหาอะไรนะครับ ไม่ได้จะบอกว่าเห้ยจดแบบนี้มันไม่ดีนะ แต่คือผมอยากลองอะไรใหม่ๆ ไง\u003c/p\u003e\n\u003cp\u003eนอกจากเรื่องจดอีกเรื่องนึงคือ Todo list ครับ หลายต่อหลายปีมากที่ผมพยายามจะอยู่กับ App todo list แต่สุดท้ายแล้วอยู่กับ App ไม่รอดถึงมันจะ Sync หลาย Platform มีฟีเจอร์เตือน นั่นนู่นนี่ก็เหอะ ไม่รอดครับ เพิ่งรู้ตัวว่า Todolist ที่รอดสำหรับผมคือ ใช้แล้วทิ้ง นั่นก็คือ เขียนลง Post-it เวิร์คสุด\u003c/p\u003e","title":"แนะนำ BuJo เมื่อชีวิตอยากติด Analog"},{"content":"ตั้งแต่ Python 3.5 เป็นต้นมา Python ได้แปลงร่างจากภาษา Duck Typing เต็มตัว ให้มีความสามารถในการใส่ Type Annotation ในโค้ดซึ่งถูกพัฒนามาตั้งแต่ปี 2014 แต่ผมค้นพบว่าหลายๆ บริษัทการเขียน Type Annotation ในภาษา Python ยังไม่แพร่หลายอย่างที่มันควร ในบล็อคนี่เลยจะพาไปรู้จักตั้งแต่เหตุผลที่ว่าทำไมเราถึงควรใส่ Type Annotation จะใช้ Type Annotation ยังไง รวมถึงกลยุทธในการเพิ่ม Type Annotation เข้าไปใน Codebase และ workflow ของเราครับ\nทำไมถึงต้องมี Type Annotation เป็นคำถามแรกเลยและคำถามสำคัญด้วย ทำไมเราถึงควรจะใส่ Type Annotation ให้กับภาษาที่เป็น Duck typing อย่าง Python ทำไมเราถึงอยากจะลดอิสระภาพในการประกาศอะไรก็ได้ ลองดูโค้ดตัวอย่างข้างล่างนี้ครับ\nดูแว็บแรกก็เหมือนจะเข้าใจง่ายใช่มั้ยครับ เป็นฟังก์ชั่นไว้ยิง request รับ url, data, headers พอผ่านไปซักหกเดือนมันเกิดคำถาม data มันรับข้อมูลแบบไหน ? มันอาจจะเป็น text ก็ได้ อาจจะเป็น dict ก็ได้ เราไม่มีทางรู้ได้เลยแต่แรกจากโค้ดว่าควรจะส่ง data หน้าตาเป็นยังไง ทีนี้เราลองมาดูฟังก์ชั่นเดียวกันที่ใส่ Type Annotation แล้วนะครับ (อย่าเพิ่งสนใจ Syntax มากนะครับ พยายามดูแบบไม่ต้องคิดอะไรมากก่อน)\nจะเห็นได้เลยว่า เนี่ย data เจ้าปัญหาเราเนี่ยมันต้องส่ง Dict มานะที่ key, value เป็น str เช่นเดียวกับ headers ส่วน return ของ ฟังก์ชั่น make_request นี่ก็คืน Tuple ของ int และ str ไปตามลำดับครับ\nอันนี้แค่ตัวอย่างง่ายๆ นะครับรับ arguments แค่ 3 ตัวและ return Tuple แค่ 2 ตัว ลองคิดภาพฟังก์ชั่นที่ทำงานซับซ้อนกว่านี้รับ arguments มากกว่านี้ เพียงแค่เราเขียน Type Annotation เพิ่มอีกนิดหน่อย สิ่งที่เราจะได้กลับคืนมาคือ\nMaintain code ง่ายขึ้นมาก เพราะเรา Explicit ไปเลยว่า arguments ตัวนี้รับอะไร และฟังก์ชั่นนี้คืนอะไร ทำให้คนอ่านเข้าใจโค้ดได้ดีขึ้น Code Review ง่ายขึ้นมากครับ เพราะคน Review ไม่จำเป็นต้องเดา Type ของฟังก์ชั่นที่กำลังดูอยู่ Debugging ง่ายขึ้น เหตุผลเดียวกันครับ ไม่จำเป็นต้องเดา Type ของฟังก์ชั่นที่เรากำลังทำอยู่ Validate assumption ระหว่างเราเขียนไปด้วยในตัว เคยมั้ยครับ เขียนฟังก์ชั่นส่งข้อมูลกันไปมาหลายๆ ที่แล้วเริ่มมึนและลึกจนไม่รู้ว่า มันส่งอะไรกัน การใส่ Type Annotation + Type Checker จะช่วย Proof ในส่วนนี้ให้ครับ ลด Cognitive Load ของ Developer ทำให้มีพื้นที่สมองส่วนที่เคยต้องใช้จำ Type เอาไปคิดส่วนอื่นมากขึ้นครับ Type Annotation หน้าตาเป็นยังไง โครงสร้างพื้นฐานของฟังก์ชั่นจะแตกต่างจากที่เราเคยเขียนโดยเพิ่ม : T ซึ่ง T ก็คือ Type ของ arguments ครับอีกส่วนหนึ่งคือ -\u0026gt; R ซึ่งก็คือ Type ของ return ของฟังก์ชั่น ตัว Type ที่เราพูดถึงกันนี่ สามารถใช้ได้ตั้งแต่ built-in Type เช่น str, int, bool, float, … ไปจนถึง collection type เช่น List, Dict, Tuple เป็นต้น แล้วจะเห็นได้ว่า Python 2 ซึ่งไม่รองรับ Syntax รูปแบบใหม่ก็จะใช้อีกแบบนึง แต่โดยรวมแล้วก็จะคล้ายๆ กัน ครับ\nตัวอย่างการเขียน Type Annotation ในแบบต่างๆ ตัวอย่างข้างบนเป็นการเขียน Type แบบง่ายๆ ครับ แต่การเขียน Type จริงๆ ยังมีรูปแบบการเขียนอีกหลายแบบมา เดี๋ยวเราจะมาลองดูกันว่าจะเขียน Type ท่าไหนได้บ้าง\nสำหรับคนขี้เกียจ ท่านี้ผมแนะนำไว้ จะได้ไม่ทำกันครับ เพราะมันมีค่าเท่ากับไม่ต้องเขียนเลย การใช้ Type Any ไม่ได้ช่วยให้โค้ดอ่านง่ายขึ้นและ Type Checker ไม่สามารถใช้ประโยชน์จากมันได้เลยครับ\nสำหรับคืนของเป็น Collection ท่านี้ตอนเขียน Type Annotation จะเข้าใจผิดง่ายมาก ถ้าไม่อ่าน Document ของ Mypy มาก่อน คือ List, Tuple, Dict หรือ Collection ต่างๆ ถ้าเราเขียนโดยใช้ dict, list, tuple ตัวแรกตรงๆ มันจะฟ้อง run-time error ครับ List, Tuple,… ที่ module typing เตรียมไว้ให้เป็น alias class ของ type พวกนั้นครับ มีโน้ตนิดหน่อยสำหรับ Tuple ใน Python 3.6 (PEP526) ได้เพิ่ม Syntax เกี่ยวกับ Type Annotation เพิ่มขึ้นมาคือ … หมายความว่า Tuple นี้จะเป็น type str ทั้งหมด\nสำหรับตัวแปรที่อาจเป็น None ในบางครั้ง arguments ที่เรารับมาอาจจะมีค่าเป็น None ได้ เราจะบอกว่า Type นี้อาจจะเป็น type บางอย่างได้และเป็น None ได้โดยใช้ type ที่ชื่อว่า Optional ครับ ท่านี้สามารถเขียนอีกรูปแบบนึงได้คือ s: str = None ครับ\nสำหรับตัวแปรที่อาจเป็นได้มากกว่า 1 type ในกรณีนี้ arguments s สามารถเป็นได้ทั้ง int หรือ str แทนที่เราจะเลือกให้มันเป็น type ใด type หนึ่ง เราสามารถให้มันเป็น Union Type ครับคือเป็นได้ทั้ง str หรือ int ท่านี้จะได้ใช้บ่อยมากๆ เวลาเราเขียน Type ของ dictionary แล้วเราจะอธิบาย value ของ dict อย่างละเอียดครับ\nสำหรับ arguments กับ return เป็น type เดียวกัน ตอนที่ผมเห็นท่านี้ครั้งแรกมันเกิดคำถามขึ้นเลยครับ ว่าจะได้ใช้เมื่อไร แต่คำถามนั้นมันเกิดก่อนผมจะเริ่มมาเขียน type annotation จริงจัง ผมค้นพบว่า บางครั้งเราเขียน type ที่ซับซ้อนมากๆ พวกที่มี Union, Optional ปนอยู่ การจะต้องมาเขียนหลายๆ รอบซ้ำๆ มัน duplicate เยอะและยาว ก็เลย define เป็น TypeVar จะง่ายกว่ามากครับ\nสำหรับ inherit type จาก type อื่น บางครั้งการใช้ built-in type อาจจะไม่สื่อความหมายเพียงพอเช่น int อาจจะเป็นเลขอะไรก็ได้ ขอแค่เป็นเลข การสร้าง type ใหม่จาก type เดิมคือคำตอบครับ ผมว่าเคสตัวอย่างนี้อธิบายได้ดีมากว่าทำไมบางครั้งเราควรสร้าง Type ใหม่ขึ้นมา\nสำหรับรับ class ไม่ใช่ object ที่ instantiate แล้วจาก class บางครั้งเราก็มีเคสที่ต้องการ type ของ class จริงๆ ไม่ใช่ Object ที่ถูกสร้างจาก Class เราต้องห่อมันด้วย Type[] ครับ ดูมีประโยชน์ในชีวิตจริงผมก็ยังไม่เคยใช้เหมือนกัน\nจริงๆ ยังมีตัวอย่างอื่นอีกเยอะมากครับแนะนำให้ไปดู Mypy syntax cheat sheet (Python 3) จะมีทุกท่าที่ผมยกตัวอย่างมา รวมถึงท่าอื่นๆ ที่ผมไม่ได้พูดถึงเช่น variable annotation ด้วยครับ\nPython เดา Type จาก Type Annotation ได้ด้วยนะเออ หัวข้องงๆ ลองดูตัวอย่างดูละกันครับ จากตัวอย่างแรกจะเห็นว่าฟังก์ชั่น f รับ arguments l ที่เป็น list ของ str แล้วข้างในฟังก์ชั่นมีตัวแปร s ที่เรียกของข้างใน list l ตัว Mypy เวลาอ่านจะทำ type inference ว่า s เนี่ยต้องเป็น str ให้เราเลย โดยที่เราไม่ต้องเขียน type ตรงตัวแปร s ก็ได้\nตัวอย่างที่สองจะเป็นการลด scope ของการ inference จะเห็นได้ว่าในฟังก์ชั่น g รับ arguments message โดยที่ message เนี่ยอาจเป็นได้ทั้ง str หรือ None ครับ ถ้าเราเช็ค type ผ่านคำสั่ง reveal_type ตรงก่อนบรรทัดที่ห้าจะได้ตามนั้น แต่เราสามารถลดความเป็นไปได้ของ type ผ่าน condition ได้ จะเห็นว่าพอเราใช้คำสั่ง reveal_type ในบรรทัดที่ 7 ความเป็นไปได้ของ message จะเหลือแค่ str ครับ\nลืมแนะนำ reveal_type ครับเป็น built-in ที่มาพร้อมกับ Mypy เอาไว้ check type ของตัวแปรได้ โดย Mypy มันจะขึ้น message บอกหน้าตาประมาณนี้ครับ\nตัว mypy จะโชว์ type ที่อ่านได้จาก reveal_type ด้วยครับ\nสร้าง Type ใหม่ผ่านการ Cast สมมติว่าเราลองทุกอย่างละทุกท่า built-in, Union, Optional (แต่ไม่ Any) นะแล้วยัง Failed อยู่ เราสามารถสร้าง type ใหม่ได้ครับกระบวนการนี้เรียกว่า Cast ลองดูตัวอย่างข้างล่างได้ครับครับ\nทำความรู้จักกับ Type Checker หลังจากที่เราเพิ่ม Type Annotation ให้กับ Codebase ของเราไปแล้ว เราก็ควรจะใช้ประโยชน์จากมันให้เต็มที่ โดยในภาษา static type อย่างเช่นภาษา C นี่คนที่ใช้ประโยชน์ตรงนี้คือ Compiler ครับที่จะ Proof ว่า ข้อมูลที่เราส่งไปมาระหว่างฟังก์ชั่นเนี่ย มันถูก Type อย่างที่มันควรจะเป็นรึยัง สำหรับ Python นั้นเราใช้ Mypy ครับ\nหน้าตาของ Mypy เวลาเจอ TypeError\nMypy เป็น static type checker ที่ถูกพัฒนาโดย Guido van Rossum มาตั้งแต่ปี 2012 ครับ ก่อนมาตรฐาน Type Annotation PEP484 ออกซะอีก โดยวิธีใช้ก็เพียงแค่สั่ง Mypy แล้วตามด้วยไฟล์ที่เราต้องการจะเช็ค Mypy ก็จะทำการอ่าน Type Annotation ให้และดูว่าส่วนประกอบต่างๆ ที่เรียกใช้มันในไฟล์นั้น เรียกใช้ตาม Type อย่างที่มันควรจะเป็นรึเปล่า ซึ่งจริงๆ แล้ว Mypy มี option เยอะกว่านั้นมากครับ แต่ผมไม่เคยใช้ฮาาา\nส่วนตัวผมเองนั้นจะไม่ใช้ Mypy ตรงๆ โดยจะใช้ผ่าน package ชื่อว่า flake8-mypy ครับ เพราะว่าโดยปกติแล้วใน Codebase ของเรามักจะลง flake8 ไว้อยู่แล้ว พอเราลง flake8-mypy ไปทำให้เราเพิ่มความสามารถของ flake8 ให้เช็ค Type Annotation ของไฟล์นั้นๆ ไปเลยด้วย แล้วโดยปกติแล้วใน Vim ผมเองจะเซต ale ให้รัน Flake8 แบบ Asynchronous อยู่แล้ว ทำให้แทบจะเช็ค Type ได้แบบเกือบจะในทันทีเลย\nNeoVim เวลา flake8-mypy แจ้งเตือนก็จะแจ้งเตือนแบบนี้แหละครับ\nPyCharm เวลาแจ้งเตือน TypeError จะเห็นว่า message แตกต่างจาก mypy แต่ก็คือเรื่องเดียวกันครับ\nสำหรับผู้ใช้ PyCharm นั้นไม่ต้องลง Plugin อะไรเลยครับ เพราะตัว PyCharm เองได้พัฒนาส่วน Type Checker ขึ้นมาเองโดยที่ไม่ขึ้นกับ Mypy เลยครับ ส่วน Text Editor ตัวอื่นก็ใช้ได้นะครับอย่าง Atom / VSCode ถ้าเซ็ตให้มันเช็ค lint จาก flake8 อยู่แล้วผมคิดว่าน่าจะไม่ต้อง config อะไรเพิ่มเติมเลย\nกลยุทธในการเพิ่ม Type Annotation เพิ่มมันเลยจะรออะไรหละ ใส่เข้าไปเลยครับ ไหนๆ เราก็รู้วิธีเขียนแล้ว แล้วก็รู้แล้วว่ามันดีขนาดนี้จะรออะไรอยู่หละครับ ใส่เข้าไปเยอะๆ แต่เดี๋ยวก่อนวิธีนี้มีข้อเสียสูงมาก เพราะเราไม่ได้ใช้ประโยชน์อะไรจาก Type Checker เลย นั่นหมายความว่า ถ้าเราเพิ่มผิดขึ้นมาเวลาแก้ทีมันจะผิดเยอะมาก แล้วเราต้องไปไล่เก็บทีละไฟล์ๆ เหนื่อยครับบอกเลย\nGradual Typing เทคนิคนี้เป็นเทคนิคที่ Instagram ใช้ครับ วิธีการก็คือเราหาฟังก์ชั่นพื้นฐานสุดที่ไม่เรียกใช้คนอื่นแล้ว เราเพิ่มจากตรงนั้นเป็นจุดแรก อันนี้สำคัญมาก เพราะถ้าเราเลือกฟังก์ชั่นที่ไม่พื้นฐานจริงๆ เราต้องแก้กลับไปกลับมาหลายรอบจนกว่าจะถูก จากนั้นเราทำการรัน Type Checker ครับตัว Type Checker ก็จะด่าเราถ้าฟังก์ชั่นที่เรียกฟังก์ชั่น basic สุดเรามันส่งค่ามาผิด type ครับ กฏข้อสำคัญคือ\nแก้เฉพาะฟังก์ชั่นที่ Type Checker ด่าเท่านั้น ฟังก์ชั่นอื่นๆ ถือว่ารับและ return Any\nวิธีการนี้จะทำให้ Codebase เราค่อยๆ เปลี่ยนจากไม่มี Type เป็นมี Type อย่างมั่นคงครับ ต้องใช้เวลาค่อยเป็นค่อยไป แต่พอถึงจุดนึง Codebase เราจะเต็มไปด้วย type และลดปัญหาเรื่อง TypeError ไปได้มากโขเลยครับ\nนอกจากค่อยๆ แก้แล้วสิ่งที่แนะนำอีกอย่างนึงคือ ควรจะใช้ mypy เช็ค Codebase โดยรวมด้วยผ่าน Continuous Integration workflow เราด้วยจะได้เป็นการป้องกันอีกชั้นว่าสิ่งที่เราพยายามเพิ่มกันมาไม่สูญหายไป\nAutomate generate type using MonkeyType อันนี้เรียกว่าเสริมเทคนิคที่แล้วละกัน การที่เราต้องมานั่งพยายามเขียน Type บางครั้งมันก็เหนื่อยมาก คนที่ Instagram (อีกแล้ว) เลยสร้าง tool ตัวนี้ขึ้นมา Monkey type เนี่ยจะไปอ่าน type จาก run-time ของ code ซึ่ง run-time อาจจะเป็น run-time จริงๆ หรือ Unit-test ก็ได้ เก็บไว้ในไฟล์จากนั้นก็ generate type ขึ้นมาจาก run-time ที่อ่านได้ แล้วเราสามารถ patch ฟังก์ชั่นได้เลย วิธีนี้เพิ่มได้เร็วมาก แต่ข้อเสียก็มากโดยเฉพาะถ้าใช้กับ Unit-test เราจะเจอ Mock type อะไรแบบนี้ก็ต้องมานั่งแก้ แต่ก็ช่วยลดเวลาไปได้ระดับนึงเลยทีเดียว ถ้าสนใจเพิ่มเติม อ่านได้ที่นี่เลยครับ\nLet your code type-hint itself: introducing open source MonkeyType Today we are excited to announce we’re open-sourcing MonkeyType, our tool for automatically adding type annotations to your Python 3 code… — Instagram Engineering, Instagram Engineering\nแล้วไงต่อ Type Annotation ยังค่อนข้างเป็นเรื่องใหม่ใน Python มากๆ ครับ เพราะฉะนั้น tooling หลายๆ อย่างเลยยังค่อนข้างน้อยอยู่ แต่ผมแนะนำสองสามที่ๆ ไปต่อได้ครับ\nถ้าอยากจะรู้เพิ่มเติมเกี่ยวกับการเขียน Type Annotation ที่ๆ ดีที่สุดที่ควรอ่านคือ official document ของ Mypy เลยครับที่นี่ http://mypy.readthedocs.io/en/latest/index.html ถ้ารีบตรงไปอ่าน Cheatsheet เลยครับ มีตัวอย่างครบแทบทุกแบบ อาจจะเป็นความบ้าส่วนตัวผมก็ได้นะ แต่ถ้าอยากศึกษาที่มาที่ไป ทำไมสุดท้ายถึงมาลงตัวรูปแบบ Annotation แบบนี้แนะนำให้ไปอ่าน PEP ที่เกี่ยวกับ Type Annotation เลยครับตามนี้เลย PEP484 PEP526 PEP544 PEP563 โพสนี้ได้แรงบันดาลใจมาหลังจากผมดู Talk นี้ครับจาก PyCascade แนะนำให้ไปดูกันเค้าเล่าสนุกมาก รวมถึง issues แปลกๆ ที่เค้าเจอตอนพยายามเพิ่ม type เข้าไปใน Codebase ของ instagram ครับ Original post at: https://yothinix.medium.com/python-type-annotation-ทำไม-python-ต้องเขียน-type-ด้วย-2559187f94ed\n","permalink":"https://yothinix-com.pages.dev/python-type-annotation/","summary":"\u003cp\u003eตั้งแต่ Python 3.5 เป็นต้นมา Python ได้แปลงร่างจากภาษา Duck Typing เต็มตัว ให้มีความสามารถในการใส่ Type Annotation ในโค้ดซึ่งถูกพัฒนามาตั้งแต่ปี 2014 แต่ผมค้นพบว่าหลายๆ บริษัทการเขียน Type Annotation ในภาษา Python ยังไม่แพร่หลายอย่างที่มันควร ในบล็อคนี่เลยจะพาไปรู้จักตั้งแต่เหตุผลที่ว่าทำไมเราถึงควรใส่ Type Annotation จะใช้ Type Annotation ยังไง รวมถึงกลยุทธในการเพิ่ม Type Annotation เข้าไปใน Codebase และ workflow ของเราครับ\u003c/p\u003e\n\u003ch1 id=\"ทำไมถงตองม-type-annotation\"\u003eทำไมถึงต้องมี Type Annotation\u003c/h1\u003e\n\u003cp\u003eเป็นคำถามแรกเลยและคำถามสำคัญด้วย ทำไมเราถึงควรจะใส่ Type Annotation ให้กับภาษาที่เป็น Duck typing อย่าง Python ทำไมเราถึงอยากจะลดอิสระภาพในการประกาศอะไรก็ได้ ลองดูโค้ดตัวอย่างข้างล่างนี้ครับ\u003c/p\u003e\n\u003cscript src=\"https://gist.github.com/yothinix/8a4bafc9228f200d30b020cb14710964.js\"\u003e\u003c/script\u003e\n\u003cp\u003eดูแว็บแรกก็เหมือนจะเข้าใจง่ายใช่มั้ยครับ เป็นฟังก์ชั่นไว้ยิง request รับ url, data, headers พอผ่านไปซักหกเดือนมันเกิดคำถาม data มันรับข้อมูลแบบไหน ? มันอาจจะเป็น text ก็ได้ อาจจะเป็น dict ก็ได้ เราไม่มีทางรู้ได้เลยแต่แรกจากโค้ดว่าควรจะส่ง data หน้าตาเป็นยังไง ทีนี้เราลองมาดูฟังก์ชั่นเดียวกันที่ใส่ Type Annotation แล้วนะครับ (อย่าเพิ่งสนใจ Syntax มากนะครับ พยายามดูแบบไม่ต้องคิดอะไรมากก่อน)\u003c/p\u003e","title":"Python Type Annotation: ทำไม Python ต้องเขียน Type ด้วย"},{"content":"ถ้าหากว่าธีมของปีที่แล้วเป็นการพัฒนาตนเองในด้านร่างกาย ปีนี้คงเป็นการพัฒนาตนเองในด้านจิตใจอย่างไม่ต้องสงสัยเลย หลายอย่างที่เคยทำก็ไม่ได้ทำ หลายอย่างที่ไม่เคยทำก็ได้ทำ ถึงแม้ปีนี้จะวุ่นวายแค่ไหน แต่ปีนี้ก็ส่งพี่จั๊วะมาย้ำสิ่งสำคัญอย่างนึงซึ่งผมหลงลืมไปคือ เราทุกคนควรจะมีเพื่อน แล้วเพื่อนนี่แหละจะพาเราผ่านความยากลำบากต่างๆ นาๆ ไปได้ 🙋‍♂️\nFinance 💰 ถ้าจะมีอะไรที่เป็นข้อผิดพลาดของชีวิตแล้วผมพยายามแก้ปัญหามันมาตลอดสองปีกว่าคือหนี้ครับ ผมเรียกได้เลยว่าผมใช้บัตรเครดิตได้ผิดหลักการจนมันนำไปสู่หนี้ก้อนใหญ่มาก จนผมขยับตัวไม่ได้ เรียกได้ว่ามีหนี้ปักกลางหลังจริงๆ ปีนี้ตลอดปีที่ผ่านมาผมเลยพยายามลดก้อนหนี้ให้ได้ ถึงแม้จะมีงานเสริมเข้ามานอกจากงานหลัก แต่มันก็จะมีกระเพื่อมขึ้นๆ ลงๆ ตลอด ไม่หมดไปซักที จนกระทั่งถึงจุดหนึ่งหลังจากที่ทุกคนปากเปียก ปากแฉะบอกให้ผมเก็บตังค์ซะที พอเก็บตังค์เท่านั้นแหละ ชีวิตเปลี่ยนเลยครับ พอเริ่มมีเงินเก็บ เราก็ไม่อยากให้มันหายไป และก็อยากให้มันเพิ่มขึ้นเรื่อยๆ ไม่อยากเอามาใช้ ผมก็เก็บเรื่อยๆ เดือนละนิดๆ หน่อยๆ จนวันที่ 29 ธ.ค. ที่ผ่านมาผมก็ไม่เหลือหนี้บัตรเครดิตแม้แต่บาทเดียวแล้ว แถมมีเงินเก็บอีกต่างหาก ✨\nความขึ้นๆ ลงๆ ของหนี้กับเงินที่มี (กราฟจาก YNAB)\nReading 📚 ปีนี้เป็นปีที่กลับมาอ่านหนังสือเยอะมากอีกครั้ง จนถึงกับต้องซื้อชั้นวางหนังสือเพิ่มเลยทีเดียว หนังสือที่อ่านปีนี้ก็มีหลายแนวตั้งแต่ Technical, Programming, จิตวิทยา, วิทยาศาสตร์, ประวัติศาสตร์ ยัน เศรษฐศาสตร์ รวมถึงไม่ได้อ่านแค่เป็นเล่มแต่ eBook ก็เพิ่มขึ้นอย่างมีนัยยะสำคัญในปีนี้ หนังสือที่ชอบที่สุดในปีนี้มีสามเล่มคือ The Miracle of Dunkirk, Moneyball และ The little book of Hygge\nนอกจากหนังสือแล้วพวก Blog, Newsletter ก็อ่านเพิ่มขึ้นเหมือนกัน จนหลายๆ ครั้งรู้สึกว่า Information Overload แล้วก็ไม่อ่านไปดื้อๆ เลย แต่ตลอดปีก็พยายามแก้ปัญหา Link Overload ซึ่งแต่ก่อนจะเก็บไว้ใน Facebook Saved พอมี Toby ออกก็เอาไปดองไว้ในนั้น พอตอนนี้มาใช้ Firefox เลยพยายามเปลี่ยนมาใช้ Pocket คู่กับ Liner ก็พอทำให้ลิ้งที่ดองมีคุณค่ามากขึ้น เพราะเรารู้ว่าเราดองไปทำไมด้วย Liner แต่ก็ยังไม่ใช่วิธีที่ดีที่สุดเพราะกับ Video Conference อย่างงี้ก็ไม่รู้จะ Highlight ยังไง ก็ยังคงตามหาวิธีที่มีประสิทธิภาพกันต่อไป\nยังเหมือนเดิม… ดองไงก็ดองอย่างนั้น\nWork 👨‍💻 ตั้งแต่ทำงานมาเกือบสี่ปี นี่เป็นปีแรกที่ไม่ได้พิมพ์บล็อคครบรอบการทำงานในแต่ละปี เพราะคิดว่า Cycle มันเปลี่ยนและมันตรงกับเดือนธันวาคม (ผมเริ่มงานปัจจุบันวันที่ 1 ธันวาคม ปีที่แล้ว) เพราะฉะนั้นเลยคิดว่าจะมาพิมพ์ไว้ใน Year in Review นี้แทน\nต้องขอบคุณ Pronto Tools อย่างนึงที่ตลอดหนึ่งปีที่ผ่านมายอมให้ได้ทำในสิ่งที่ชอบคือ Back-end เป็นหลักแล้วทำอย่างอื่นอย่าง Front-end หรือ Infra นิดๆ หน่อยๆ ปีนี้ได้อยู่กับ Django REST Framework ตลอดทั้งปีจนจากเคยเป็นคนแปลกหน้ากัน Serializer ยังไม่รู้จักเลย จนเดี๋ยวนี้แทบจะขึ้นโปรเจ็คได้โดยไม่เปิด Document เลย นอกจากนั้นแล้วยังได้ทำ Celery กับ Elasticsearch ตั้งแต่ 0 ด้วย เลยได้รู้ได้เจออะไรแปลกๆ เยอะมาก ถ้ามีโอกาสคงได้เขียนเล่าให้ฟังกัน\nContribution ของงานหลวงในปีนี้ (GitHub)\nContribution ของงานนอกในปีนี้ (gitlab)\nแต่มีเรื่องดีก็ต้องมีเรื่องแย่ ปีนี้เป็นปีที่ทำงานหนักเหมือนกัน จนลืมคำว่า Work-Life Balance ไปเลย แล้วค่อนข้างจะมีปัญหาด้านจิตใจอย่างมากหลายเดือนเลย โชคดีที่ Pronto มีโครงการ Big Little แล้วโชคดีที่ได้ Big เป็นพี่ออน ซึ่งแทบจะไม่รู้จักเลยตอนแรก แต่ตลอดเวลาหลายเดือน แม้จะคุยกันไม่กี่ครั้ง แต่ทุกครั้งที่คุยกันจะได้มุมมองใหม่ๆ ที่เปลี่ยนไปจากคนที่เคยมองอะไรอย่างที่ตัวเองเห็น กลายเป็นคนที่มองอะไรหลายมุมมากขึ้น เข้าใจโลกอย่างที่มันควรจะเป็นมากขึ้น และเข้าใจคำว่า Susu! ใน Pronto Value มากขึ้นด้วย\nไปเป็น Product Owner งาน Woman Techmaker ที่ ม.เกษตร ศรีราชา\nนอกจากงานประจำการอยู่ Pronto Tools นี่ก็ทำให้มีโอกาสได้รู้จักกับคนใหม่ๆ อยู่ตลอด นอกจากงาน Meetup ที่ไปกันเกือบตลอดแล้ว ปีนี้ก็เป็นอีกปีที่ได้ไป CE Smart Career แต่เปลี่ยนบริษัทก็แปลกดี แต่ก็ยังสนุกเหมือนเดิมที่ได้กลับไปโม้ให้น้องๆ ฟังว่าเราทำอะไร นอกจากนั้นยังจับพลัดจับพลูไปเป็น Product Owner ที่งาน Woman Techmaker ที่ ม.เกษตร ศรีราชา ซึ่งก็เป็นครั้งแรกที่ได้ใช้ APIStar ปั้น API ขึ้นมาแบบด่วนๆ คืนเดียวเสร็จ มีไปเตะบอลกับตีปิงปองกับ Kaidee และอีกหลาย Event แต่ที่ชอบที่สุดของปีนี้คือการได้ไปโม้ Asynchronous Programming in Python ที่ Code Mania ด้วย 🐍\nนอกจากงานหลวงแล้ว ปีนี้เป็นปีที่ทำงานนอกเยอะมาก ต้องขอบคุณฟอร์ซที่หางานมาให้ทำเรื่อยๆ ไม่งั้นคงไม่ได้เจอประสบการณ์ที่ต้องแบกคอมหนีพายุฝน น้ำท่วม คนรุมเป็นร้อย รับโหลดเป็นพัน ฯลฯ ข้อดีของการได้ทำงานนอกคือ ผมได้ทดลองอะไรใหม่ๆ เยอะมาก ฟอร์ซก็ได้ระบบที่ทำให้ Workflow มันดีขึ้นก็วินๆ ทั้งคู่ ถึงแม้ว่าบางช่วงมันจะเหนื่อยมากๆ เพราะ requirements เปลี่ยนบ่อย แต่โดยรวมแล้วก็มีความสนุกดี และคิดว่าคงจะได้ลุยอะไรมันๆ ด้วยกันอีกปีหน้า\nเป็นสติ๊กเกอร์ที่มีความทรงจำเยอะมาก\nTravel 🏝 ปีนี้ไม่ค่อยได้ไปเที่ยวบ่อยเหมือนปีที่ผ่านๆ มาเพราะงานยุ่งมากด้วยส่วนหนึ่ง ปีนี้ถ้าจะไปต่างจังหวัด ไม่กลับบ้านก็จะไปทำงานซะมากกว่า (ชลบุรี, ขอนแก่น) แต่ถ้าจะมีไปเที่ยวจริงๆ ก็มีที่ไปภูเก็ตครั้งแรกในชีวิต เพิ่งเคยนั่งเครื่องบินลอยอยู่เหนือทะเลครั้งแรก (ภาพเหมือนใน FSX มาก) แต่ก็ยังไม่รู้จักภูเก็ตเท่าไร ส่วนใหญ่อยู่บนรถมากกว่า\nถึงแม้จะเป็นเที่ยวจริงๆ จังๆ ครั้งเดียว แต่เป็นครั้งเดียวในปีนี้ที่รู้สึกผ่อนคลายมาก เหมือนทิ้งโลกไว้ข้างหลังในเวลาไม่กี่วัน ปีนี้เลยคุยกันกับตั๊กว่า ปีหน้าเราต้องไปเที่ยวให้บ่อยกว่านี้นะ แล้วเจอกันที่เชียงใหม่\nView from above VTSP\nอื่นๆ 📦 ปีนี้ซื้อคีย์บอร์ดใหม่เป็น CODE Keyboard (Tenkeyless) Brown switch เพราะว่าหนวกหู Ducky ตัวเก่ามาก ปีนี้ซื้อ Fit Bit ซะทีเป็นอะไรที่อยากได้มาหลายปีมาก สุดท้ายซื้อ Surge เหตุผลเดียวเลยคือมันมี GPS ในตัว ปีนี้ซื้อหูฟังใหม่ Marshall mid Bluetooth หลังจากซื้อไม่กี่วัน Marshall Mode EQ ตัวเก่า พังทันที คืองงมาก ฆ่าตัวตายเหรอ ปีนี้ตอนเป็นลีดเดอร์ที่พรอนโต้ได้เริ่ม Policy ที่จะแชร์ Knowledge กันง่ายๆ โดยสร้างห้อง #learn-today ใน Slack ไม่เคยคิดเลยว่าห้องที่สร้างผ่านไปหลายเดือนก็ยังมีความ Active อยู่และหลายคนชอบถึงแม้จะไม่ได้โพสอะไรทุกวันเหมือนแรกๆ แล้วก็ตาม ไอเดียเริ่มต้นของห้องนี้มาจาก blog นี้ What did you learn at work today? Automatic check-ins is one of my favorite features in the new Basecamp 3. We have a bunch of them. Some social, like What are you reading? or What did you do this weekend?, others practical, like W… — Signal v. Noise, DHH\nปีนี้คิดว่าจะย้ายมาเขียนบน Medium ละลาก่อน Blogger ที่อยู่คู่กันมานาน ว่างๆ ก็เข้าไปอ่านได้ที่ https://yothinix.blogspot.com ปีนี้เขียนบล็อคที่มีคนอ่านเกินพันวิวอยู่สองครั้งคือ What I actually do, when I have to go to work at 7.00 เมื่อวานเป็นวันสุดท้ายที่ลีดเดอร์พี่แก้มกับนัทจะเป็นลีดเดอร์เลยมีเกมส์ส่งท้ายมาเล่นกัน เป็นเกมส์ให้สร้างคำจากตัวอักษรที่กำหนดให้ยาวที่สุด ใครยาวน้อยสุดคนนั้นจะโดนทำโทษจากกล่องทำโทษที่ทุกคนช่วยกันเขียนบทลงโทษกันมาทั้งทีม (ซึ่งปกติเอาไว้ทำโทษคนมาสาย) ทีนี้ผมแพ้เลยได้จับใบทำโทษมา 1 ใบโจทย์ คือ มาทำงานก… — Blogger, Yothin Muangsommuk\n10 Python libraries ที่เราชอบในปี 2017 ช่วงท้ายปีเป็นช่วงที่คนส่วนใหญ่จะนั่งนึกถึงว่าเราทำอะไรมาบ้าง ตลอดปีที่ผ่านมา แล้วจะทำอะไรต่อไปในปีข้างหน้า ปกติแล้วทุกปีช่วงท้ายๆ ปีผมจะชอบรอ Tech Radar ออกซึ่งก็จะได้รู้จัก Tools และ Techniques ใหม่ๆ ที่ Proof แล้วว่ — Yothinix, Yothin Muangsommuk\nปีนี้ซื้อเฟอร์นิเจอร์ใหม่สามชิ้นคือ โต๊ะกินข้าว ชั้นหนังสือ และก็โคมไฟ ปีนี้ตัดแว่นไปสองครั้ง ครั้งที่สองถึงรู้ว่าสายตาตัวเองเปลี่ยนแล้วกลายเป็นเอียง 100 สั้น 50 ทั้งสองข้างเลย ปีนี้เป็นครั้งแรกในชีวิตที่คบกับใครเกินหนึ่งปี กะตั๊กได้ทำลายทุกสถิติที่โยธินมีก่อนหน้านี้หมดเกลี้ยง รวมทั้งน้ำหนักตัวของโยธินด้วยที่ทำ new high เป็นที่เรียบร้อยแล้ว และผ่านมาหนึ่งปีก็ยังยืนยันคำเดิมว่า มีแฟนนี่แหละจะทำให้ชีวิตเราดีขึ้น Super bowl LI ดูอยู่ออฟฟิส Pronto และโชคดีที่ได้ดู เพราะเป็น Comeback ที่เป็นตำนานไปอีกหลายปีแน่ๆ เพลงที่ฟังบ่อยที่สุดของปีนี้คือ I Got You ของวง Mild ไม่ค่อยแปลกใจเท่าไร เพราะไปทำงานกับฟอร์ซทุกครั้งก็เจอวง Mild ทุกครั้ง ฟังจนติดหูเลย หนังที่ชอบปีนี้มี Dunkirk กับ Star Wars: The Last Jedi ปีนี้ดูหนังน้อยลงเยอะมาก และถ้าดูก็จะไปดูแต่ IMAX แทบไม่ได้ดูโรงธรรมดาเลย แต่ถ้าเป็นหนังที่ดูบ่อยที่สุดในปีนี้ก็จะมีสองเรื่องเหมือนกันคือ Moneyball ชอบดูเวลารู้สึกเหนื่อย ท้อแท้กับชีวิตเวลาเห็นชีวิตของ Billy Beane จะรู้สึกว่า เห้ยมันยังมีคนที่เจอปัญหายากกว่าเราอยู่อีกนะ กับ Arrival อันนี้เพราะกะตั๊กชอบดูมากแล้วต้องดูด้วย ปีนี้ดูซีรีย์ไม่เยอะมากเพราะยังคง Commitment ที่จะเก็บ Star Trek ให้หมดอยู่ แต่ผ่านมาหนึ่งปีเต็มๆ นี่ก็ยังเก็บ Star Trek: The Next Generation ไม่หมด (เหลืออีก 2 Season) แถมปีนี้มี Star Trek: Discovery ออกมาอีกก็เลยยิ่งช้าไปอีก ปีนี้ดู Talk Show สองครั้งหัวปีท้ายปีเลย รู้สึกดีใจที่ได้เห็นพี่ยูมาไกลขนาดนี้ จากวันที่เคยไปฟังที่ร้าน Z Book ปีนี้ยังสอบนักบินไม่ติดอยู่ดี มันมีคำพูดนึงที่คนคุมสอบพูดไว้ในปีนี้ แล้วมันเจ็บลึกไปถึงข้างใน แต่ก่อนก็ไม่เข้าใจหรอก แต่ตอนนี้เข้าใจแล้ว คือ มีความฝันอย่างเดียวไม่ได้… ต้องมีความพยายามด้วย บางคนสอบมาสามปี บางคนสอบมาสี่ปี…\nสุดท้ายปีนี้มีนามบัตรแล้วหล่อมาก อิอิ ✨ รับจ้างเขียนงู ทั่วราชอาณาจักร\nOriginal post at: https://yothinix.medium.com/2017-7e8c5e8a7598\n","permalink":"https://yothinix-com.pages.dev/2017/","summary":"\u003cp\u003eถ้าหากว่าธีมของปีที่แล้วเป็นการพัฒนาตนเองในด้านร่างกาย ปีนี้คงเป็นการพัฒนาตนเองในด้านจิตใจอย่างไม่ต้องสงสัยเลย หลายอย่างที่เคยทำก็ไม่ได้ทำ หลายอย่างที่ไม่เคยทำก็ได้ทำ ถึงแม้ปีนี้จะวุ่นวายแค่ไหน แต่ปีนี้ก็ส่งพี่จั๊วะมาย้ำสิ่งสำคัญอย่างนึงซึ่งผมหลงลืมไปคือ \u003cem\u003eเราทุกคนควรจะมีเพื่อน\u003c/em\u003e แล้วเพื่อนนี่แหละจะพาเราผ่านความยากลำบากต่างๆ นาๆ ไปได้ 🙋‍♂️\u003c/p\u003e\n\u003ch1 id=\"finance-\"\u003eFinance 💰\u003c/h1\u003e\n\u003cp\u003eถ้าจะมีอะไรที่เป็นข้อผิดพลาดของชีวิตแล้วผมพยายามแก้ปัญหามันมาตลอดสองปีกว่าคือหนี้ครับ ผมเรียกได้เลยว่าผมใช้บัตรเครดิตได้ผิดหลักการจนมันนำไปสู่หนี้ก้อนใหญ่มาก จนผมขยับตัวไม่ได้ เรียกได้ว่ามีหนี้ปักกลางหลังจริงๆ ปีนี้ตลอดปีที่ผ่านมาผมเลยพยายามลดก้อนหนี้ให้ได้ ถึงแม้จะมีงานเสริมเข้ามานอกจากงานหลัก แต่มันก็จะมีกระเพื่อมขึ้นๆ ลงๆ ตลอด ไม่หมดไปซักที จนกระทั่งถึงจุดหนึ่งหลังจากที่ทุกคนปากเปียก ปากแฉะบอกให้ผมเก็บตังค์ซะที พอเก็บตังค์เท่านั้นแหละ ชีวิตเปลี่ยนเลยครับ พอเริ่มมีเงินเก็บ เราก็ไม่อยากให้มันหายไป และก็อยากให้มันเพิ่มขึ้นเรื่อยๆ ไม่อยากเอามาใช้ ผมก็เก็บเรื่อยๆ เดือนละนิดๆ หน่อยๆ จนวันที่ 29 ธ.ค. ที่ผ่านมาผมก็ไม่เหลือหนี้บัตรเครดิตแม้แต่บาทเดียวแล้ว แถมมีเงินเก็บอีกต่างหาก ✨\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/2017/1-87UfXt_QYtwOH6DpbXwehQ_hu_77a7e4b8134560e3.webp\"\n       srcset=\"/2017/1-87UfXt_QYtwOH6DpbXwehQ_hu_2c003e0d9693c5e2.webp 480w, /2017/1-87UfXt_QYtwOH6DpbXwehQ_hu_77a7e4b8134560e3.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"449\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eความขึ้นๆ ลงๆ ของหนี้กับเงินที่มี (กราฟจาก YNAB)\u003c/em\u003e\u003c/p\u003e\n\u003ch1 id=\"reading-\"\u003eReading 📚\u003c/h1\u003e\n\u003cp\u003eปีนี้เป็นปีที่กลับมาอ่านหนังสือเยอะมากอีกครั้ง จนถึงกับต้องซื้อชั้นวางหนังสือเพิ่มเลยทีเดียว หนังสือที่อ่านปีนี้ก็มีหลายแนวตั้งแต่ Technical, Programming, จิตวิทยา, วิทยาศาสตร์, ประวัติศาสตร์ ยัน เศรษฐศาสตร์ รวมถึงไม่ได้อ่านแค่เป็นเล่มแต่ eBook ก็เพิ่มขึ้นอย่างมีนัยยะสำคัญในปีนี้ หนังสือที่ชอบที่สุดในปีนี้มีสามเล่มคือ \u003ca href=\"https://www.amazon.com/Miracle-Dunkirk-Story-Operation-Dynamo-ebook/dp/B0078X73NO\"\u003eThe Miracle of Dunkirk\u003c/a\u003e, \u003ca href=\"https://www.amazon.com/Moneyball-Art-Winning-Unfair-Game/dp/0393324818\"\u003eMoneyball\u003c/a\u003e และ \u003ca href=\"https://www.amazon.com/Little-Book-Hygge-Danish-Penguin-ebook/dp/B01EXVIW06\"\u003eThe little book of Hygge\u003c/a\u003e\u003c/p\u003e","title":"2017"},{"content":"ช่วงท้ายปีเป็นช่วงที่คนส่วนใหญ่จะนั่งนึกถึงว่าเราทำอะไรมาบ้าง ตลอดปีที่ผ่านมา แล้วจะทำอะไรต่อไปในปีข้างหน้า ปกติแล้วทุกปีช่วงท้ายๆ ปีผมจะชอบรอ Tech Radar ออกซึ่งก็จะได้รู้จัก Tools และ Techniques ใหม่ๆ ที่ Proof แล้วว่า Work เลยคิดว่า คงจะดีไม่น้อยที่เราจะได้แบ่งปันอะไรบ้าง ในมุมมองของการทำงานที่ Pronto Tools นี้\n\\1. pipenv 🗄 Source: https://docs.pipenv.org/\nปีนี้ถ้าจะไม่พูดถึง pipenv ก็คงจะไม่ได้ เพราะ library ตัวนี้ได้เปลี่ยน workflow ในการ develop python ไปอย่างสิ้นเชิง พร้อมกับความสามารถใหม่ๆ ที่เพิ่มเข้ามาจน Python.org ให้การรับรองว่าเป็น packaging tool ที่ควรจะใช้แทน pip ที่ใช้กันมาหลายปี\nจุดเด่นหลักๆ ของ pipenv คือการเพิ่ม Pipfile มาแทนที่ requirements.txt ที่เป็น pattern พื้นฐานกันมาหลายปี ด้วย syntax แบบ TOML ที่ง่ายกว่ามาก และมีความสามารถมากกว่าเช่น สามารถกำหนด version ของ Python ที่ต้องการจะใช้ run ได้, สามารถกำหนด development package ได้ ทำให้เราไม่ต้องแยก file requirements.txt สำหรับแต่ละ environment อีกต่อไป นอกจากนั้นแล้ว pipenv ยัง เพิ่ม Pipfile.lock มาด้วย​ซึ่งทำให้เรามั่นใจได้ว่าจะได้ Package ที่ถูกต้องจริงๆ จาก PyPI\nนอกจากจุดเด่นที่กล่าวมาข้างต้นแล้วใน version หลังๆ pipenv ยังได้เพิ่มความสามารถในการเช็ค security vulnerability ผ่านคำสั่ง pipenv check ซึ่งทำให้เรามั่นใจในความปลอดภัยของ Package ที่เราใช้มากยิ่งขึ้นไปอีก\n\\2. Pendulum ⏳ Source: https://pendulum.eustace.io/\nที่พรอนโต้เราชอบ Arrow มากครับ หลังๆ แทบจะเอามาใช้แทน Datetime ตรงๆ เลย แต่ปีนี้มีเรา Pendulum ออกมา และมันน่าสนใจมาก\nข้อดีของ Pendulum เลยคือ ตัวมันเอง Inherit มาจาก DateTime class ของ Python เพราะฉะนั้นเราแทบจะแทนที่ datetime ด้วย Pendulum ได้ทั้งหมดเลย นอกจากนั้นแล้วตัว Pendulum ยังแก้ปัญหา edge case ต่างๆ ที่เจอใน Arrow ด้วย ทำให้เราไม่ลังเลเลยที่จะเปลี่ยนไปใช้มัน\n\\3. Uplink 📡 Source: http://uplink.readthedocs.io/en/latest/\nโปรเจ็คของเราเองหลายโปรเจ็คต้องต่อกับ Service API ข้างนอกครับ ซึ่งลำพังแค่ lib requests ที่เราใช้กันอย่างหนักหน่วงจะเริ่มมีความซับซ้อนขึ้น เพราะต้องยิงหลายๆ Endpoint ใน service เดียว วิธีที่เราแก้ปัญหาในเรื่องนี้คือเราสร้าง Class ขึ้นมาครอบ Service ที่เราจะใช้ แล้วเรียกการใช้งานผ่าน Class นั้นแทนโดยที่ข้างในสุดท้ายแล้วยังเป็น requests ที่ทำหน้าที่ในการยิง API อยู่\nปีนี้เราไปเจอ Uplink ซึ่งทำหลายๆ อย่างคล้ายกับ Design ที่เรากล่าวมาข้างต้นมาก แต่ใช้เป็น Decorator ในการ define endpoint แทน รวมถึงจัดการ header กับ timeout ได้ใน decorator เลย สะดวกมากๆ ครับ\n\\4. MonkeyType 🙊 Source: https://github.com/Instagram/MonkeyType\nตั้งแต่ Python 3.6 เป็นต้นมา สิ่งหนึ่งที่เราตื่นเต้นมากคือการมี Type Annotation ให้ใช้ แต่เพราะ code base ที่เรามียังใหญ่อยู่มาก การใช้งาน Type Annotation ของเราเลยยังจำกัดอยู่เฉพาะส่วนที่มันสำคัญจริงๆ ของระบบไม่กี่ส่วน\nเมื่อไม่กี่สัปดาห์ที่ผ่านมา Instagram ได้เปิดตัว MonkeyType ซึ่งเป็น Library ไว้ Generate type annotation จาก runtime ซึ่ง ก่อนหน้านี้ Dropbox ได้เปิดตัว PyAnnotate มาแล้วแต่ยังเป็น Python 2 style annotation เราเลยไม่สนใจมัน\nเราค้นพบว่าการประยุกต์ใช้ MonkeyType กับ code base เราง่ายกว่าที่คิดมาก เนื่องจาก เรามี unit test คลุมทุกส่วนของระบบอยู่แล้ว แล้วเราใช้ pytest ในการ execute test การเอา MonkeyType มาใช้จึงแค่ให้มันอ่าน trace จาก Pytest runner แล้วให้ MonkeyType generate type annotation ออกมาหลังจากนั้น\n\\5. Mimesis 🦑 Source: https://github.com/lk-geimfari/mimesis\nเรามักจะมีปัญหาเสมอเวลาต้องคิดชื่อ หรือข้อมูลต่างๆ เช่น ที่อยู่ เบอร์โทร​ ฯลฯ ยิ่งระบบที่เก็บข้อมูลเยอะมากๆ อย่าง Pronto World แล้วยิ่งคิดยากมาก กว่าจะใส่ข้อมูลคนๆ นึงให้ครบได้ จนกระทั่งเรามาเจอ Mimesis\nMimesis เป็น Library ที่ช่วยจัดการ mock ข้อมูลต่างๆ ให้ ข้อดีคือเราไม่จำเป็นต้องมานั่งนึกข้อมูลเองว่าจะตั้งชื่ออะไร ใช้ที่อยู่อะไร เบอร์โทรศัพท์อะไร จริงๆ แล้วมีมากกว่านั้นอีก นอกจากนั้นแล้วยังมี translation หลายภาษามากๆ แต่ท้ายที่สุดแล้ว ประโยชน์สูงสุดที่ได้จาก Mimesis คือเราประหยัดเวลาในการคิดเรื่องที่ ไม่จำเป็นต้องคิดไปได้อีกหนึ่งเรื่องเลย\n\\6. APIStar ✨🚀✨🌟 Source: https://github.com/encode/apistar\nที่พรอนโต้เราใช้ Django กันมานาน แล้วเราค่อนข้างจะเป็นแฟนพันธ์แท้กับ Django REST Framework ด้วย ซึ่งนั่นทำให้เราตื่นเต้นมากเมื่อ Tom Christie สร้าง Framework สำหรับทำ Web API ตัวใหม่ขึ้นมา\nจุดเด่นหลักๆ เลยคือ API Star ใช้ประโยชน์ของ Type Annotation ใน Python 3.6 ได้อย่างมีประสิทธิภาพมาก ถ้าเราชิน Request / Response Cycle ของ Django แล้วตัวนี้จะเปลี่ยนวิธีคิดเราไปเลย เพราะมองว่า API หนึ่ง Endpoint คือ function เดี่ยวๆ ที่รับ Argument แล้ว Return Value ออกไป นอกจากนั้นแล้วยังมี API Documentation ในตัวเอง generate มาจาก code ที่เป็น view ทำให้เรามั่นใจได้ว่า เราจะไม่ตกหล่นการเขียน Document ของ view ไหนออกไป\n\\7. Box 📦 Source: https://github.com/cdgriffith/Box\nBox เป็น Library เล็กๆ ที่ไม่มีอะไรซับซ้อนเลย มันแค่แปลง Dictionary ใน Python ให้สามารถใช้ dot notation ในการเข้าถึงข้อมูลได้ บางคนอาจจะสงสัยว่า แล้วทำไมไม่ใช้ Nametuple หรือประกาศ Class ไปเลย ใช่ครับมันทำได้ แต่จะทำให้มันซับซ้อนขนาดนั้นทำไม ตัว Box เองเนี่ยพอใช้งานจริง แล้วมันเบามากๆ แทบจะโยน Dict ทั้งก้อนแล้ว Access จาก Object ของ Box แทนเลย เบาแถมโค้ดสะอาดขึ้นไม่ต้องมี quote กับ bracket มากวนใจ\n\\8. Python-Fire 🔥 Source: https://github.com/google/python-fire\nเคยเขียน Script Python แล้วอยากทำให้มันทำอะไร ได้เยอะๆ เหมือนโปรแกรมใน cli ของ Linux เช่น curl บ้างมั้ยครับ กว่าจะทำได้ สมัยก่อนเราต้องใช้ argparse ซึ่งเป็น standard library ที่อยู่คู่ Python มายาวนาน มา define ว่าจะรับค่าอะไร ผ่าน arguments หน้าตาเป็นยังไง\nFire เนี่ยง่ายๆ เลยครับ แค่เขียน function หรือ class หรือ Python object อะไรก็ได้ แล้วครอบมันด้วย Fire object มันจะทำการแปลง arguments, Method ฯลฯ อะไรก็ตามที่มัน call ได้ให้เป็น Option ใน CLI แค่นั้น จบครับ โคตรง่าย จนผมยังตกใจเลยว่านี่มันเสร็จแล้วเหรอ\n\\9. Magic Wormhole 🌪 Source: https://github.com/warner/magic-wormhole\nอันนี้อาจจะไม่ใช่ Library ที่สร้างในปีนี้ แต่ผมเพิ่งมาค้นพบในปีนี้ ในสมัยโบราณกาลเราใช้ scp ในการ copy ไฟล์ระหว่างเครื่อง ถัดมาเราก็รู้จัก rsync ที่ทำให้ชีวิตมันง่ายขึ้นไปอีก แต่มันยังง่ายไปกว่านั้นได้อีกครับด้วย Magic Wormhole\nMagic Wormhole ทำให้การส่งไฟล์ข้ามกันระหว่างสองเครื่อง เป็นเรื่องง่ายโคตรๆ โดยฟังส่งก็แค่พิมพ์ wormhole send \u0026lt;file\u0026gt; พอพิมพ์เสร็จจะได้โค้ดมาซึ่งโค้ดที่ว่าเนี่ย สามารถอ่านออกเสียงได้ เหมาะกับการพูดบอกโค้ดกันเช่น 7-crossover-clockwork ทีนี้ฝั่งรับก็แค่มี wormhole ลงอยู่แล้วพิมพ์ wormhole receive หลังจากนั้นมันจะถามโค้ดจากฝั่งส่งก็พิมพ์ไป แค่นี้ก็ได้ ง่ายมากไม่ต้องจำ IP / host อะไรเลย\n\\10. PrettyPrinter 🖨 Source: https://prettyprinter.readthedocs.io/en/latest/\nสุดท้ายเป็น Library เล็กๆ อีกแล้ว เพิ่งออกมาได้ยังไม่ถึงเดือนเลย แต่ก็เอามาใช้แล้ว แล้วเราชอบมาก คือ PrettyPrinter พอพูดแบบนี้แล้วก็จะเกิดคำถามอีกว่า ทำไมไม่ใช้ pprint ที่มีอยู่แล้ว\nเหตุผลหลักๆ เลยคือ pprint ไม่รู้จัก Django ครับ เราเลยใช้ความสามารถของ PrettyPrinter เต็มที่มากๆ เวลา debug ไม่ต้องมานั่ง กดดู Model Instance แต่ละตัวว่ามีค่าอะไรบ้าง พอใช้ตัวนี้แล้ว มันกระจายให้ละเอียดและ Indent ให้แบบสวยงามพร้อมสีสันสดใสเลยครับ\nแน่นอนว่าตลอดหนึ่งปีที่ผ่านมา Library ที่เกิดขึ้นใหม่ใน Python Community มันไม่ได้มีแค่นี้หรอกครับ และยังมีอีกหลายตัวที่ผมอยากพูดถึง แต่อาจจะยาวเกินไปสำหรับ Story นี้ผมเลยจะ List Packages ที่ผมเจอและชอบที่เหลือไว้ตรงนี้แทน\n* asyncssh (https://github.com/ronf/asyncssh)\n* requestium (https://github.com/tryolabs/requestium)\n* Ray (https://github.com/ray-project/ray)\n* newspaper (https://github.com/codelucas/newspaper)\nOriginal post at: https://yothinix.medium.com/10-python-libraries-ที่เราชอบในปี-2017-143c06a70619\n","permalink":"https://yothinix-com.pages.dev/10-python-libraries-we-like-2017/","summary":"\u003cp\u003eช่วงท้ายปีเป็นช่วงที่คนส่วนใหญ่จะนั่งนึกถึงว่าเราทำอะไรมาบ้าง ตลอดปีที่ผ่านมา แล้วจะทำอะไรต่อไปในปีข้างหน้า ปกติแล้วทุกปีช่วงท้ายๆ ปีผมจะชอบรอ \u003ca href=\"https://www.thoughtworks.com/radar\"\u003eTech Radar \u003c/a\u003eออกซึ่งก็จะได้รู้จัก Tools และ Techniques ใหม่ๆ ที่ Proof แล้วว่า Work เลยคิดว่า คงจะดีไม่น้อยที่เราจะได้แบ่งปันอะไรบ้าง ในมุมมองของการทำงานที่ Pronto Tools นี้\u003c/p\u003e\n\u003ch1 id=\"1-pipenv-\"\u003e\\1. pipenv 🗄\u003c/h1\u003e\n\u003cp\u003eSource: \u003ca href=\"https://docs.pipenv.org/\"\u003ehttps://docs.pipenv.org/\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eปีนี้ถ้าจะไม่พูดถึง \u003cstrong\u003epipenv\u003c/strong\u003e ก็คงจะไม่ได้ เพราะ library ตัวนี้ได้เปลี่ยน workflow ในการ develop python ไปอย่างสิ้นเชิง พร้อมกับความสามารถใหม่ๆ ที่เพิ่มเข้ามาจน \u003ca href=\"https://packaging.python.org/tutorials/managing-dependencies/#managing-dependencies\"\u003ePython.org ให้การรับรอง\u003c/a\u003eว่าเป็น packaging tool ที่ควรจะใช้แทน pip ที่ใช้กันมาหลายปี\u003c/p\u003e\n\u003cp\u003eจุดเด่นหลักๆ ของ \u003cstrong\u003epipenv\u003c/strong\u003e คือการเพิ่ม \u003cem\u003ePipfile\u003c/em\u003e มาแทนที่ \u003cem\u003erequirements.txt\u003c/em\u003e ที่เป็น pattern พื้นฐานกันมาหลายปี ด้วย syntax แบบ \u003cstrong\u003eTOML\u003c/strong\u003e ที่ง่ายกว่ามาก และมีความสามารถมากกว่าเช่น สามารถกำหนด version ของ Python ที่ต้องการจะใช้ run ได้, สามารถกำหนด development package ได้ ทำให้เราไม่ต้องแยก file \u003cem\u003erequirements.txt\u003c/em\u003e สำหรับแต่ละ environment อีกต่อไป นอกจากนั้นแล้ว \u003cstrong\u003epipenv\u003c/strong\u003e ยัง เพิ่ม \u003cem\u003ePipfile.lock\u003c/em\u003e มาด้วย​ซึ่งทำให้เรามั่นใจได้ว่าจะได้ Package ที่ถูกต้องจริงๆ จาก PyPI\u003c/p\u003e","title":"10 Python libraries ที่เราชอบในปี 2017"},{"content":"เมื่อวานเป็นวันแรกที่ผมไปเรียนคลาส TOEIC ของสถาบันมาครับ คลาสนี้เรียนฟรีเสียแค่ค่าสอบ 700 ซึ่ง อันที่จริงแล้วผมเล็งจะเรียนมาตั้งแต่ต้นเทอมแล้ว แต่มัวแต่ไปทำอย่างอื่นอยู่เลยไปลงทะเบียนไม่ทันสุดท้ายเลยมาตกกับรอบสองซึ่งก็คือรอบนี้ แต่ถึงแม้มันจะเป็นแค่วันแรก แต่มันทำให้ผมนึกถึงอะไรหลายๆ อย่างๆ เลยทีเดียว\nอย่างแรกมักจะมีใครซักคนมาถามผมอยู่บ่อยๆ ว่าทำยังไงถึงจะเรียนภาษาอังกฤษเก่ง ผมเจอคำถามนี้มาแทบจะตั้งแต่อยู่ประถม ซึ่งตอนเด็กๆ ผมก็ตอบไม่ได้หรอกครับ ตอนมัธยมก็ไม่ชัวร์ แต่พออยู่มหาลัยผมพอจะรู้คำตอบแล้ว จริงๆ แล้วผมไม่ได้เก่งภาษาอังกฤษเลยนะครับ เรื่อง Grammar, Tense, Part of Speech ฯลฯ ผมไม่เคยรู้เรื่องครับ อันนี้สารภาพตามตรงเลย แต่ผมโตมาในครอบครัวที่ภาษาอังกฤษแทบจะอยู่รอบตัวตลอดเวลา คุณพ่อกับคุณแม่ผมทั้งสองท่านทำงานสถานีวิทยุ แล้วทั้งสองท่านโดยเฉพาะคุณพ่อมีรสนิยมชอบฟังเพลงสากลมาตั้งแต่ก่อนผมเกิด ตั้งแต่จำความได้นี่ผมก็ได้ยินเพลงสากลเข้ามาในหูละ ตั้งแต่ The Beatle, Bee Gees, Carpenter, Rod Stewart ฯลฯ ซึ่งทำให้ตอนผมอยู่ชั้นประถมหรือมัธยมก็รู้สึกแปลกๆ เหมือนกันที่ตัวเองชอบเพลงพวกนี้ ในขณะที่เพื่อนฟังลาบานูน, บอดี้แสลม หรือโปเตโต้ อะไรเหล่านี้ นอกจากนั้นแล้วท่านยังเป็นคนชอบดูหนังอีกด้วย และไม่แปลกเลยถ้าบ้านเราจะดูหนังที่ซับเป็นภาษาอังกฤษแต่ก็บ่อยครั้งมาก พอขึ้นมัธยมจำได้ว่าตอนมัธยมต้นช่วงนั้นกระแสเกาหลีมาแรงมาก ผมไม่เคยสนเลยครับอาจจะเป็นเพราะผมเป็นผู้ชายด้วยก็เลยไม่ค่อยกรี๊ดวงเกาหลีซักเท่าไร ซึ่งระหว่างนั้นผมก็เริ่มรู้จักซีรีย์เข้ามาในชีวิตเรื่องแรกๆ ที่ดูแล้วติดน่าจะเป็น NCIS (ซึ่งปัจจุบันก็ยังฉายอยู่) Even Steven ใน Disney Channel และอีกหลายๆ เรื่อง ซึ่งผ่านมาในชีวิตผมยันเข้ามหาลัย ที่ซึ่งไร้ซึ่งทีวีส่วนตัว แต่การมีอินเตอร์เน็ตทำให้เราหาของเหล่านี้ไม่ยากเท่าไรและแน่นอนครับว่าในสมัยนี้หนัง mkv มันฝังซับมาให้เลย เพราะฉะนั้นแล้วการเลือกดูเสียง ENG มันได้อรรถรสกว่าฟังเสียงไทยเยอะ ซึ่งในที่สุดแล้วผมก็เพิ่งมาค้นพบว่าน่าจะเป็นสิ่งเหล่านี้แหละที่เป็นเหตุผลหลักที่ผมไม่เคยรู้สึกแปลกกับภาษาอังกฤษซักเท่าไรเลย\nตอนผมฝึกงานที่หน่วยจะมีกฎเล็กๆ อยู่กฎหนึ่งคือไม่อนุญาตให้พูดภาษาไทยในตอนครึ่งเช้าก่อนพักเที่ยง ถึงแม้จะเป็นคนไทยด้วยกันก็ตาม เพราะนายอย่างให้ฝึกใช้ภาษาอังกฤษ ซึ่งผมก็ต้องทำตามไปด้วย ซึ่งแรกๆ ก็ยากอยู่เพราะใช้ว่าทุกคนพูดภาษาอังกฤษได้ถนัดเหมือนกัน แต่พออยู่ไปนานๆ ก็เริ่มชิน ผมเริ่มเรียนรู้ว่าถ้าอธิบายด้วยคำพูดไม่ได้ก็ทำให้ดูเลยง่ายกว่า นอกจากนั้นแล้วในกลุ่มอินเทิร์นด้วยกันผมก็ไม่รู้ว่าใครตั้งกฎอะไรขึ้นมา แต่พอคุยกันวงใหญ่ในเฟสบุ๊ค ก็มักจะคุยกันด้วยภาษาอังกฤษไม่ใช่ภาษาไทย อันนี้ก็แปลกแต่ผมว่ามันก็เจ๋งดีแหะ เรื่องสุดท้ายเกี่ยวกับทริปเกาะช้างที่ผมเพิ่งไปเมื่อสุดสัปดาห์ที่ผ่านมา คือภาษาอังกฤษเนี่ยถึงเราจะรู้จักได้รับมันมามาก แต่ถ้าไม่ได้ใช้มันก็ขึ้นสนิมได้ เพราะฉะนั้นแล้วเนี่ยการพาตัวเองเข้าไปหาโอกาสที่จะใช้ภาษาอังกฤษได้นับว่าเป็นการฝึกที่ได้ประสิทธิภาพมากกว่าหนังสือระดับนึงเลยทีเดียว ต้องย้อนไปถึงคุณพ่อผมก่อน คุณพ่อผมเป็นคนที่เรียกได้ว่าอัธยาศัยดีมาก และคุยกับคนเก่งมาก อาจจะเป็นเพราะเคยเป็นนักข่าวมาก่อน เวลาไปเที่ยวแล้วเจอฝรั่งท่านชอบเข้าไปทัก เข้าไปคุยด้วยเสมอ ซึ่งตอนเด็กๆ ผมก็ไม่เคยเข้าใจว่าท่านจะเข้าไปทักทำไม แต่พอโตขึ้น ถึงเริ่มเข้าใจว่าการที่ท่านเข้าไปทักบ่อยๆ ทำให้ท่านใช้ภาษาอังกฤษได้ดีระดับนึง หรืออาจจะทำลายกำแพงซึ่งหลายคนมีคือ การไม่กล้าที่จะพูดตอบโต้ กลับมาที่เกาะช้าง ผมเจอหนุ่มสาวชาวเกาหลีสองคนกำลังหลงหรืออาจจะหลงทางอยู่ ซึ่งตอนแรกผมก็ไม่เห็นแต่พอเพื่อนเรียกถึงเห็น แล้วได้คุยตอบโต้ จริงๆ แล้วมันไม่ได้ยากอะไรเลย เพราะภาษาอังกฤษก็ไม่ใช่ภาษาหลักของ \u0026ldquo;เขา\u0026rdquo; และของ \u0026ldquo;เรา\u0026rdquo; ด้วยการสื่อสารที่ว่าสิ่งสำคัญคือจับคีย์เวิร์ดให้ได้แล้วพยายามเดาว่าเขาพยายามสื่ออะไร ซึ่งเรื่องนี้ก็จบลงด้วยดีคือ สองคนนั้นกลับมาทางเดียวกับผมและเพื่อนจนถึงกรุงเทพ\nเรื่องสุดท้ายเป็นเรื่องของหนังสือครับ ผมเป็นคนชอบอ่านหนังสือมาตั้งแต่สมัยประถม สมัยนั้นยังไม่บ้าพลังพอที่จะไปอ่านภาษาอังกฤษเป็นเล่มๆ พออยู่มัธยมพี่ชายผมเริ่มซื้อหนังสือของเพนกวิน รีดเดอร์มาให้ส่วนใหญ่แล้วเป็นหนังสือที่แปลงมาจากภาพยนต์เล่มจะไม่หนามาก พอมีกำลังใจอ่านเล่มแรกๆ ที่อ่านจบคือ Apollo 11 กับ About a Boy ซึ่งจุดเริ่มต้นเล็กๆ นั้นอาจจะยังไม่ส่งผลระยะสั้นแต่ในระยะยาว พอเข้ามหาลัย ชีวิตต้องเริ่มปรับตัวมาอ่าน Text ผมก็ยังมีปัญหาอยู่แต่ปัญหาไม่ได้อยู่ที่ภาษาแต่เป็นเพราะมันต้องเข้าใจสมการไปด้วย ซึ่งแรกๆ ก็ยากแต่พออยู่กับมันไปนานๆ มันก็เริ่มน่ารักขึ้น แต่สาเหตุหลักของหนังสือที่บังคับให้ผมอ่านคือ ข่าวครับ ในสายไอทีการจะรอข่าวมาแปลไทยตอนนี้ผมถือเป็นเรื่องที่เสียเวลามาก จึงไปคว้าข่าวมาอ่านก่อนเลยตามเว็บดังๆ ไม่ว่าจะเป็น Wired, Lifehacker หรือ Hackernews ซึ่งผมอ่านแทบจะทุกวันทำให้นอกจากจะได้ความรู้ในสายไอทีตลอดแล้ว ยังได้ใช้ภาษาอังกฤษทุกวันอีกด้วย\nสุดท้ายจริงๆ ผมว่าจะพูดแค่นิดเดียวเอาไปเอามาก็เยอะเหมือนกันแหะ ถ้าคุณยังไม่รู้ว่าจะเริ่มใช้ภาษาอังกฤษยังไง ก็ลองปรับวิธีการใช้ชีวิตจากไม่เคยฟังเพลงสากลลองฟังดูบ้าง จากไม่เคยดูหนังเสียง/ซับ Eng ก็ลองดูบ้าง สิ่งเหล่านี้ผมไม่รับรองว่าจะได้ผลกับทุกคน แต่ผมเชื่อว่าการที่เราได้อยู่ท่ามกลางสภาวะแวดล้อมแบบนั้นทำให้เราเรียนรู้ภาษาได้เร็วมาก (ซึ่งผมก็ว่ามันอาจจะจริงเพราะเดี๋ยวนี้ผมเริ่มมาดูซีรีย์ญี่ปุ่นแล้วเริ่มคุ้นกับคำญี่ปุ่นบางคำแล้ว) ไม่แน่คุณอาจจะชอบมันแล้วมีความสุขกับมันมากกว่าที่คิดตอนแรกก็เป็นได้ แล้วผมขอทิ้งท้ายด้วยคำคมที่ผมได้มาจากเมื่อวานแล้วผมชอบมันมากจากอาจารย์ที่สอน TOEIC คลาสผมคือ\n💡 Vocabulary is your best friend\u0026hellip; and also your worst enemy\nภาพข้างบนจาก facebook \u0026ldquo;we love NewEducation World\u0026rdquo;\nOriginal post at: https://yothinix.blogspot.com/2014/01/environment.html\n","permalink":"https://yothinix-com.pages.dev/learning-english-is-about-environment/","summary":"\u003cp\u003eเมื่อวานเป็นวันแรกที่ผมไปเรียนคลาส TOEIC ของสถาบันมาครับ คลาสนี้เรียนฟรีเสียแค่ค่าสอบ 700 ซึ่ง อันที่จริงแล้วผมเล็งจะเรียนมาตั้งแต่ต้นเทอมแล้ว แต่มัวแต่ไปทำอย่างอื่นอยู่เลยไปลงทะเบียนไม่ทันสุดท้ายเลยมาตกกับรอบสองซึ่งก็คือรอบนี้ แต่ถึงแม้มันจะเป็นแค่วันแรก แต่มันทำให้ผมนึกถึงอะไรหลายๆ อย่างๆ เลยทีเดียว\u003c/p\u003e\n\u003cp\u003eอย่างแรกมักจะมีใครซักคนมาถามผมอยู่บ่อยๆ ว่าทำยังไงถึงจะเรียนภาษาอังกฤษเก่ง ผมเจอคำถามนี้มาแทบจะตั้งแต่อยู่ประถม ซึ่งตอนเด็กๆ ผมก็ตอบไม่ได้หรอกครับ ตอนมัธยมก็ไม่ชัวร์ แต่พออยู่มหาลัยผมพอจะรู้คำตอบแล้ว จริงๆ แล้วผมไม่ได้เก่งภาษาอังกฤษเลยนะครับ เรื่อง Grammar, Tense, Part of Speech ฯลฯ ผมไม่เคยรู้เรื่องครับ อันนี้สารภาพตามตรงเลย แต่ผมโตมาในครอบครัวที่ภาษาอังกฤษแทบจะอยู่รอบตัวตลอดเวลา คุณพ่อกับคุณแม่ผมทั้งสองท่านทำงานสถานีวิทยุ แล้วทั้งสองท่านโดยเฉพาะคุณพ่อมีรสนิยมชอบฟังเพลงสากลมาตั้งแต่ก่อนผมเกิด ตั้งแต่จำความได้นี่ผมก็ได้ยินเพลงสากลเข้ามาในหูละ ตั้งแต่ The Beatle, Bee Gees, Carpenter, Rod Stewart ฯลฯ ซึ่งทำให้ตอนผมอยู่ชั้นประถมหรือมัธยมก็รู้สึกแปลกๆ เหมือนกันที่ตัวเองชอบเพลงพวกนี้ ในขณะที่เพื่อนฟังลาบานูน, บอดี้แสลม หรือโปเตโต้ อะไรเหล่านี้ นอกจากนั้นแล้วท่านยังเป็นคนชอบดูหนังอีกด้วย และไม่แปลกเลยถ้าบ้านเราจะดูหนังที่ซับเป็นภาษาอังกฤษแต่ก็บ่อยครั้งมาก       \u003cbr\u003e\nพอขึ้นมัธยมจำได้ว่าตอนมัธยมต้นช่วงนั้นกระแสเกาหลีมาแรงมาก ผมไม่เคยสนเลยครับอาจจะเป็นเพราะผมเป็นผู้ชายด้วยก็เลยไม่ค่อยกรี๊ดวงเกาหลีซักเท่าไร ซึ่งระหว่างนั้นผมก็เริ่มรู้จักซีรีย์เข้ามาในชีวิตเรื่องแรกๆ ที่ดูแล้วติดน่าจะเป็น NCIS (ซึ่งปัจจุบันก็ยังฉายอยู่) Even Steven ใน Disney Channel และอีกหลายๆ เรื่อง ซึ่งผ่านมาในชีวิตผมยันเข้ามหาลัย ที่ซึ่งไร้ซึ่งทีวีส่วนตัว แต่การมีอินเตอร์เน็ตทำให้เราหาของเหล่านี้ไม่ยากเท่าไรและแน่นอนครับว่าในสมัยนี้หนัง mkv มันฝังซับมาให้เลย เพราะฉะนั้นแล้วการเลือกดูเสียง ENG มันได้อรรถรสกว่าฟังเสียงไทยเยอะ ซึ่งในที่สุดแล้วผมก็เพิ่งมาค้นพบว่าน่าจะเป็นสิ่งเหล่านี้แหละที่เป็นเหตุผลหลักที่ผมไม่เคยรู้สึกแปลกกับภาษาอังกฤษซักเท่าไรเลย\u003c/p\u003e","title":"เรียนภาษาอังกฤษมันเป็นเรื่องของ ENVIRONMENT"},{"content":"ในชีวิตเรามักจะเจอใครซักคนมาคอยบอกเสมอว่าเราทำอย่างนั้นไม่ได้หรอกเราทำอย่างนี้ไม่ได้หรอกซึ่งในบางครั้งเสียงนั้นมันก็มาจากภายในตัวเราเองถ้านับจนถึงวันนี้ผมก็กลับมาเขียนโปรแกรมแบบจริงๆจังๆมาได้เกือบจะปีนึงแล้วคำถามคือก่อนหน้านั้นผมไปทำอะไรอยู่แล้วอะไรทำให้ผมกลับมา\nถ้าใครเคยได้ดูหนังเรื่อง Ratatouille (พ่อครัวตัวจี๊ดหัวใจคับโลก) คงคุ้นเคยกับประโยคที่กล่าวไว้ว่า \u0026ldquo;ใครๆ ก็ทำอาหารได้\u0026rdquo; ซึ่งเป็นคำกล่าวของเชฟกุ๊สโตว์พ่อครัวที่เป็นแรงบันดาลใจให้เรมี่ (หนูในเรื่อง) เริ่มทำอาหารเรมี่มีข้อจำกัดทุกอย่างที่จะทำให้ตัวเองไม่สามารถทำอาหารได้รวมถึงตัวเรมี่เองนั้นเป็นหนูซึ่งสำหรับพ่อครัวแล้วหนูแทบจะเป็นศัตรูเป็นสัญลักษณ์ของความสกปรกและไม่ควรอยู่ในห้องครัวแต่มันเองก็ยังมีพรสวรรค์อยู่ข้อหนึ่งคือมีประสาทสัมผัสในการรับกลิ่นที่เหนือกว่าหนูทั่วไปสามารถแยกแยะองค์ประกอบที่อยู่ในอาหารออกมาได้ประกอบกับแรงบันดาลใจจากการแอบไปดูรายการทำอาหารในทีวีในบ้านของมนุษย์เป็นจุดเริ่มต้นให้เรมี่กล้าที่จะทำอาหารจริงๆเมื่อถึงโอกาส\nหลังจากเรียนวิชา Data Structure เสร็จตอนอยู่ปี 2 ตลอดสองสามปีที่ผ่านตัวผมเองนั้นแทบไม่ได้จับการเขียนโปรแกรมแบบจริงจังอีกเลยซึ่งในระหว่างนั้นสิ่งที่สนใจส่วนใหญ่ก็จะเป็นการ Config ระบบหรือบริการต่างๆบน Linux ซึ่งก็ไม่ใช่ว่างานนี้มันไม่สนุกนะครับการแก้ปัญหาในการติดตั้งระบบต่างๆให้มันเข้ากับ Environment ของเราได้นั้นเป็นเรื่องที่ท้าทายพอสมควรเลยทีเดียวต้องใช้ทักษะในการวิเคราะห์ปัญหาจากสิ่งที่ Terminal มันแสดงผลออกมารวมถึงไฟล์ Log ที่อยู่ในเครื่องฯลฯและมักจะมีบริการหรือเทคโนโลยีใหม่ๆให้มาทดลองติดตั้งเสมอจนกระทั่งเมื่อขึ้นปี 4 ถึงแม้ผมจะทำงานกับ Linux ได้ดีแต่เมื่อต้องเลือกที่จะทำ Project ทำอะไรที่เราอยู่กับมันไปหนึ่งปีเต็มผมเลือกที่จะเขียนโปรแกรมแทนซึ่งนอกจากมันจะดูท้าทายเพราะผมไม่ได้ทำอะไรเกี่ยวกับการเขียนโปรแกรมมาเกือบสองปีแล้วสาเหตุที่ผมเลือกนั้นก็แทบไม่ต่างกับเรมี่คือผมมีแรงบันดาลใจซึ่งแรงบันดาลใจที่ว่านั้นก็คืออไจล์ที่ผมพูดถึงบ่อยมากจนหลายๆคนเริ่มจะเบื่อแล้ว\nสิ่งที่ผมเรียนรู้มาตลอดเกือบปีที่กลับมาเขียนโปรแกรมคือใครๆก็เขียนโปรแกรมได้ครับซึ่งไม่ต่างจากการทำอาหารอย่างที่ผมกล่าวในข้างต้นเลยเวลาเรามีปัญหาที่เราต้องการจะแก้เราจะเลือกใช้โค้ดของคนอื่นที่หาได้ทั่วไปใน Internet ที่สมัยนี้แทบจะหาไม่ยากเลยเพราะมีคนแก้ไว้หมดแล้วหรือเราจะพยายามแก้ปัญหานั้นด้วยตัวเองไม่ต่างจากการที่เราจะเลือกกินบะหมี่กึ่งสำเร็จรูปที่แค่เอาน้ำใส่ถ้วยฉีกผงชูรสใส่หรือเราจะลงทุนเข้าครัวปรุงอาหารที่เราอยากกินขึ้นมาเองแน่นอนครับมันอิ่มเหมือนกันเหมือนกับที่งานเสร็จได้เหมือนกันแต่จะอร่อยมั้ยและยอมเสียเวลาทำมันมากแค่ไหนนั่นแหละครับคือสิ่งที่แต่ละคนเลือกต่างกัน\nตอนเราเริ่มต้นทำอาหารถ้าเราคาดหวังว่าเราจะทำอาหารหรูระดับภัตตาคารได้ตั้งแต่ครั้งแรกที่เข้าครัวรับรองว่าตกลงมาเจ็บแน่ครับแล้วอาจจะเกลียดการทำอาหารไปเลยตลอดกาลแต่ถ้าเราเริ่มต้นจากจุดเล็กๆก่อนอย่างเช่นการทำไข่เจียวง่ายๆเชื่อมั้ยครับว่ามันสามารถเป็นแรงผลักดันให้เราทำอาหารที่ต้องใช้วิธีทำที่ซับซ้อนขึ้นได้นั่นแหละครับสุดท้ายแล้วไม่ได้ต่างจากการเขียนโปรแกรมเลย\nสุดท้ายแล้วความรักครับ ไม่ใช่ทุกคนครับที่รักการเขียนโปรแกรมเหมือนกับที่ผมก็ไม่ได้รักการทำอาหารซักเท่าไรแต่คนเราทุกคนมีโอกาสตกหลุมรักได้ครับถ้าเจอคนที่ใช้ในเวลาที่เหมาะผมมาเจอคนที่ใช่คืออไจล์ (อีกแล้ว) ในเวลาที่เหมาะ (ก่อนเริ่มทำโปรเจ็คหนึ่งเดือน) นั่นแหละครับเป็นสิ่งที่ทำให้ผมกลับมาเขียนโปรแกรมได้สนุกอีกครั้งและเริ่มที่จะเรียนรู้ว่าการเขียนโปรแกรมมันไม่ได้มีแค่ \u0026ldquo;การเขียนโปรแกรม\u0026rdquo; เพียงอย่างเดียวและผมยังยินดีที่จะแนะนำเธอ (อไจล์) ให้ใครก็ตามที่อยากจะรู้จักอยู่เสมอเพราะผมเชื่อว่าถ้าเขาเห็นเธอในแบบที่ผมเห็นแล้วหละก็เขาอาจจะตกหลุมรักเธอเหมือนที่ผมเป็นก็เป็นได้\nOriginal post at: https://yothinix.blogspot.com/2014/01/anyone-can-cook.html\n","permalink":"https://yothinix-com.pages.dev/anyone-can-cook/","summary":"\u003cp\u003eในชีวิตเรามักจะเจอใครซักคนมาคอยบอกเสมอว่าเราทำอย่างนั้นไม่ได้หรอกเราทำอย่างนี้ไม่ได้หรอกซึ่งในบางครั้งเสียงนั้นมันก็มาจากภายในตัวเราเองถ้านับจนถึงวันนี้ผมก็กลับมาเขียนโปรแกรมแบบจริงๆจังๆมาได้เกือบจะปีนึงแล้วคำถามคือก่อนหน้านั้นผมไปทำอะไรอยู่แล้วอะไรทำให้ผมกลับมา\u003c/p\u003e\n\u003cp\u003eถ้าใครเคยได้ดูหนังเรื่อง Ratatouille (พ่อครัวตัวจี๊ดหัวใจคับโลก) คงคุ้นเคยกับประโยคที่กล่าวไว้ว่า \u0026ldquo;\u003cem\u003eใครๆ ก็ทำอาหารได้\u003c/em\u003e\u0026rdquo; ซึ่งเป็นคำกล่าวของเชฟกุ๊สโตว์พ่อครัวที่เป็นแรงบันดาลใจให้เรมี่ (หนูในเรื่อง) เริ่มทำอาหารเรมี่มีข้อจำกัดทุกอย่างที่จะทำให้ตัวเองไม่สามารถทำอาหารได้รวมถึงตัวเรมี่เองนั้นเป็นหนูซึ่งสำหรับพ่อครัวแล้วหนูแทบจะเป็นศัตรูเป็นสัญลักษณ์ของความสกปรกและไม่ควรอยู่ในห้องครัวแต่มันเองก็ยังมีพรสวรรค์อยู่ข้อหนึ่งคือมีประสาทสัมผัสในการรับกลิ่นที่เหนือกว่าหนูทั่วไปสามารถแยกแยะองค์ประกอบที่อยู่ในอาหารออกมาได้ประกอบกับแรงบันดาลใจจากการแอบไปดูรายการทำอาหารในทีวีในบ้านของมนุษย์เป็นจุดเริ่มต้นให้เรมี่กล้าที่จะทำอาหารจริงๆเมื่อถึงโอกาส\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/anyone-can-cook/_MAN3525_hu_35c7bca465357a94.webp\"\n       srcset=\"/anyone-can-cook/_MAN3525_hu_70d9bc84714fe452.webp 480w, /anyone-can-cook/_MAN3525_hu_7b2c65add830bfe4.webp 960w, /anyone-can-cook/_MAN3525_hu_35c7bca465357a94.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"954\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eหลังจากเรียนวิชา Data Structure เสร็จตอนอยู่ปี 2 ตลอดสองสามปีที่ผ่านตัวผมเองนั้นแทบไม่ได้จับการเขียนโปรแกรมแบบจริงจังอีกเลยซึ่งในระหว่างนั้นสิ่งที่สนใจส่วนใหญ่ก็จะเป็นการ Config ระบบหรือบริการต่างๆบน Linux ซึ่งก็ไม่ใช่ว่างานนี้มันไม่สนุกนะครับการแก้ปัญหาในการติดตั้งระบบต่างๆให้มันเข้ากับ Environment ของเราได้นั้นเป็นเรื่องที่ท้าทายพอสมควรเลยทีเดียวต้องใช้ทักษะในการวิเคราะห์ปัญหาจากสิ่งที่ Terminal มันแสดงผลออกมารวมถึงไฟล์ Log ที่อยู่ในเครื่องฯลฯและมักจะมีบริการหรือเทคโนโลยีใหม่ๆให้มาทดลองติดตั้งเสมอจนกระทั่งเมื่อขึ้นปี 4 ถึงแม้ผมจะทำงานกับ Linux ได้ดีแต่เมื่อต้องเลือกที่จะทำ Project ทำอะไรที่เราอยู่กับมันไปหนึ่งปีเต็มผมเลือกที่จะเขียนโปรแกรมแทนซึ่งนอกจากมันจะดูท้าทายเพราะผมไม่ได้ทำอะไรเกี่ยวกับการเขียนโปรแกรมมาเกือบสองปีแล้วสาเหตุที่ผมเลือกนั้นก็แทบไม่ต่างกับเรมี่คือผมมีแรงบันดาลใจซึ่งแรงบันดาลใจที่ว่านั้นก็คืออไจล์ที่ผมพูดถึงบ่อยมากจนหลายๆคนเริ่มจะเบื่อแล้ว\u003c/p\u003e\n\u003cp\u003eสิ่งที่ผมเรียนรู้มาตลอดเกือบปีที่กลับมาเขียนโปรแกรมคือใครๆก็เขียนโปรแกรมได้ครับซึ่งไม่ต่างจากการทำอาหารอย่างที่ผมกล่าวในข้างต้นเลยเวลาเรามีปัญหาที่เราต้องการจะแก้เราจะเลือกใช้โค้ดของคนอื่นที่หาได้ทั่วไปใน Internet ที่สมัยนี้แทบจะหาไม่ยากเลยเพราะมีคนแก้ไว้หมดแล้วหรือเราจะพยายามแก้ปัญหานั้นด้วยตัวเองไม่ต่างจากการที่เราจะเลือกกินบะหมี่กึ่งสำเร็จรูปที่แค่เอาน้ำใส่ถ้วยฉีกผงชูรสใส่หรือเราจะลงทุนเข้าครัวปรุงอาหารที่เราอยากกินขึ้นมาเองแน่นอนครับมันอิ่มเหมือนกันเหมือนกับที่งานเสร็จได้เหมือนกันแต่จะอร่อยมั้ยและยอมเสียเวลาทำมันมากแค่ไหนนั่นแหละครับคือสิ่งที่แต่ละคนเลือกต่างกัน\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/anyone-can-cook/IMG_3462_hu_d051b610a6526e41.webp\"\n       srcset=\"/anyone-can-cook/IMG_3462_hu_c0caf82f9c0b18d0.webp 480w, /anyone-can-cook/IMG_3462_hu_bafac5f2ab4245cf.webp 960w, /anyone-can-cook/IMG_3462_hu_d051b610a6526e41.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"1080\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eตอนเราเริ่มต้นทำอาหารถ้าเราคาดหวังว่าเราจะทำอาหารหรูระดับภัตตาคารได้ตั้งแต่ครั้งแรกที่เข้าครัวรับรองว่าตกลงมาเจ็บแน่ครับแล้วอาจจะเกลียดการทำอาหารไปเลยตลอดกาลแต่ถ้าเราเริ่มต้นจากจุดเล็กๆก่อนอย่างเช่นการทำไข่เจียวง่ายๆเชื่อมั้ยครับว่ามันสามารถเป็นแรงผลักดันให้เราทำอาหารที่ต้องใช้วิธีทำที่ซับซ้อนขึ้นได้นั่นแหละครับสุดท้ายแล้วไม่ได้ต่างจากการเขียนโปรแกรมเลย\u003c/p\u003e\n\u003cp\u003eสุดท้ายแล้วความรักครับ ไม่ใช่ทุกคนครับที่รักการเขียนโปรแกรมเหมือนกับที่ผมก็ไม่ได้รักการทำอาหารซักเท่าไรแต่คนเราทุกคนมีโอกาสตกหลุมรักได้ครับถ้าเจอคนที่ใช้ในเวลาที่เหมาะผมมาเจอคนที่ใช่คืออไจล์ (อีกแล้ว) ในเวลาที่เหมาะ (ก่อนเริ่มทำโปรเจ็คหนึ่งเดือน) นั่นแหละครับเป็นสิ่งที่ทำให้ผมกลับมาเขียนโปรแกรมได้สนุกอีกครั้งและเริ่มที่จะเรียนรู้ว่าการเขียนโปรแกรมมันไม่ได้มีแค่ \u0026ldquo;\u003cu\u003eการเขียนโปรแกรม\u003c/u\u003e\u0026rdquo; เพียงอย่างเดียวและผมยังยินดีที่จะแนะนำเธอ (อไจล์) ให้ใครก็ตามที่อยากจะรู้จักอยู่เสมอเพราะผมเชื่อว่าถ้าเขาเห็นเธอในแบบที่ผมเห็นแล้วหละก็เขาอาจจะตกหลุมรักเธอเหมือนที่ผมเป็นก็เป็นได้\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eOriginal post at: \u003ca href=\"https://yothinix.blogspot.com/2014/01/anyone-can-cook.html\"\u003ehttps://yothinix.blogspot.com/2014/01/anyone-can-cook.html\u003c/a\u003e\u003c/p\u003e","title":"ใครๆ ก็ทำอาหารได้ (ANYONE CAN COOK)"},{"content":"เมื่อเย็นนี้ผมกับน้องๆในชมรมมีโอกาสไปกินเนื้อย่างมาครับจริงๆแล้วจุดประสงค์ของการไปกินเนื้อย่างครั้งนี้ไม่มีอะไรเลยนอกจากความอยากอยากและอยากที่สั่งสมมานานหลายสัปดาห์ระหว่างที่กินๆอยู่มีน้องคนหนึ่งพูดขึ้นมาว่า \u0026ldquo;กินเนื้อย่างนี่มันอไจล์มั้ยพี่\u0026rdquo; ซึ่งหลังจากคุยกันในวงเนื้อผมสรุปคร่าวๆได้ว่าการกินเนื้อย่างกับน้องๆหรือเพื่อนมันไม่ต่างอะไรกับการทำโปรเจ็คซอฟท์แวร์เลยครับ\nเรามามองที่ฝั่งเนื้อย่างก่อน ตอนที่เราเข้ามาในร้านทุกคนจะเลือกตำแหน่งที่จะนั่ง ที่ตัวเองจะกินได้สบายที่สุด บางคนเลือกที่จะนั่งตรงข้ามคนที่กินเก่งที่สุดเพราะ ถ้าอิ่มเมื่อไรมันจะได้กินแทนเรา ในกรณีนีนี้ผมไปกันห้าคน แบ่งกันเป็น 2 เตา ซึ่งน่าจะเดาไม่ยากว่าเตาหนึ่งก็จะมี 2 คนรับผิดชอบเป็นหลัก และมีน้องคนหนึ่งเป็นตัวเสริมอยู่ระหว่าง 2 เตานี้ พอเลือกที่นั่งได้แล้วพนักงานก็จะมารับออเดอร์ซึ่งการกินแบบบุฟเฟ่เราก็สั่งในสิ่งที่เราอยากกิน มากน้อยแล้วแต่ศรัทธา พนักงานก็รับออเดอร์ไป แล้วหลังจากนั้นเราก็รอ ระหว่างนี้เราจะตัดกลับมาที่โปรเจ็คซอฟท์แวร์กันก่อน ในโปรเจ็คซอฟท์แวร์ทีมๆ หนึ่งจะประกอบไปด้วยคนที่เชี่ยวชาญในแต่ละสาขาที่แตกต่างกัน จริงอยู่ที่ Agile มักจะบอกไว้ว่า Role ในทีมมันเป็นแค่สิ่งสมมติ แต่ถ้าเรามองในความสามารถจริงๆ ก็จะมีคนที่เชี่ยวชาญแต่ละสาขาอยู่นอกจากนั้นยังมีเรื่องของ Senior กับ Junior อีกซึ่งก็คล้ายๆ กับการที่เราเลือกนั่งตรงข้ามกับคนที่กินเก่งกว่าในเตาเดียวกัน เมื่อเราฟอร์มทีมขึ้นมาได้แล้วสิ่งต่อไปคือรับงานจากลูกค้า ในกรณีนี้มันจะกลับกันเลยขอข้ามกลับไปที่ฝั่งกินเนื้อย่างกันต่อ\nพอเนื้อที่สั่งมาถึง ซึ่งมันก็มักจะมากันในปริมาณมากๆ พร้อมๆ กันหลายอย่าง ตามที่แต่ละคนสั่งไป ซึ่ง ก็ขึ้นอยู่กับสไตล์ในการกินของแต่ละคนว่าชอบกินอะไรก่อน กินอะไรหลัง หรือบางคน กินอย่างละนิดอย่างละหน่อย ให้รสชาติเปลี่ยนไปเปลี่ยนมาในปาก ก็แล้วแต่สไตล์ ทุกคนจะรับผิดชอบในสิ่งที่ตัวเองสั่งมาในกรณีที่อิ่มแล้ว และเลือกที่จะช่วยกันกินในสิ่งที่คนอื่นกินไม่ไหวแล้ว ถ้ายังไหวอยู่นะ (ซึ่งก็อุดมคติมาก เพราะถ้าอิ่มจริงๆ ก็มักจะเกี่ยงกันหรือในกรณีที่เห็นวันนี้ย่างให้แล้วส่งให้ถึงจานเลย) เวลาเราเก็บ Requirement จากลูกค้ามา ซึ่งก็สารภาพตามตรงว่าผมก็ไม่เคยเก็บจากลูกค้าจริงๆ เพราะทำแค่โปรเจ็คของปีสี่ แต่สิ่งที่เกิดขึ้นและคล้ายกันคือสไตล์การทำงานมันไม่ต่างอะไรกับสไตล์การกินเลย เราเลือกในสิ่งที่เราชอบทำก่อน (หรือในบางกรณี ทำในสิ่งที่ง่ายกว่าก่อน) ในกรณีเวลาเราทำ Scrum เราต้องทำ Sprint Planning ซึ่งมักจะเลือก Requirement ที่สำคัญที่สุดมาทำก่อนคนเลือกคือใคร คือลูกค้า แต่ในกรณีนี้ลูกค้าคือตัวเองถามว่าจะเลือกอะไร แว็บนี้แหละที่แนวคิดแบบ Scrum มันโผล่เข้ามาและเห้ย มันจริง เราทำมันอยู่ทุกวันแหะ เราเลือกสิ่งที่เราอยากกิน (หรืออยากทำ) มาทีละนิดใส่ลงไปในเตาแต่ละรอบ ไม่ต่างจากการเลือกงานมาทำในแต่ละ Sprint เลย ซึ่งในเตาแรกเนี่ย จะคล้ายๆ เป็นการประเมินว่าในเตาหนึ่งมันวางเนื้อได้สูงสุดกี่ชิ้น รอบต่อไปเราจะกะได้โดยประมาณว่าจะวางได้เท่าไร ไม่ว่าเนื้อนั้นจะมาแบบลูกเต๋า เป็นแผ่น หรือเป็นเนื้อคนละชนิดก็ตาม\nสิ่งที่ผมสังเกตุเห็นอีกอย่างคือในแต่ละรอบของเตารอบที่ 2-3 เป็นรอบที่เรากินได้มีความสุขที่สุดและมี Momentum มากที่สุด (รวมถึงเนื้ออร่อยสุดด้วย) ไม่ต่างอะไรกับการทำ Scrum ที่ Sprint แรกมักจะยังงงๆอยู่แต่พอ Sprint 2-3 จะเริ่มจับจังหวะและเริ่มคล่องตัวได้แต่ปัญหาของเนื้อย่างก็ไม่ต่างจากการเขียนโปรแกรมอีกพอเราทำไปจนถึง Sprint ที่ 4 หรือรอบเตาที่ 4 เนื้อในกระเพาะก็เริ่มเยอะขึ้นไม่ต่างจากการที่เรามี Code base มากขึ้นเมื่อเราทำโปรเจ็คไปซักระยะซึ่งจะทำให้การเพิ่มอะไรเข้ามาใน Sprint หลังๆมันยากลำบากยิ่งขึ้น (ในกรณีกินเนื้อย่างคืออิ่ม)\nสุดท้ายที่ผมเห็นคือการเล่นแบบเป็นทีมเวลากินเนื้อย่างถ้าต่างคนต่างกินสุดท้ายแล้วก็จะจุกตายกันไปหมดแล้วจากมีความสุขจะกลายเป็นความทุกข์กลับมาไม่ต่างจากการทำซอฟท์แวร์ที่ถ้าต่างคนต่างทำสุดท้ายงานก็เละและเราก็จะไม่มีความสุขกับการที่เราทำมันเลยซึ่งถ้าเรากินกันเป็นทีมแน่นอนว่าเราจะคอยระวังหลังให้เพื่อนร่วมทีมเราจะไม่โยนขึ้ (หรือกรณีนี้คือเนื้อ) เมื่อเราอิ่มแล้วให้กับเพื่อนร่วมทีมเราจะค่อยๆกินไปด้วยกันจนกระทั่งถึงจุดที่เราพอเราก็จะออกจากร้านไปอย่างมีความสุขไปด้วยกันแต่สำหรับวันนี้ผมจุกมากครับ\nปล.ที่เขียนมาทั้งหมดในข้างต้นมาจากอารมณ์ล้วนๆอิ่มมากครับ\nOriginal post at: https://yothinix.blogspot.com/2014/01/blog-post_17.html\n","permalink":"https://yothinix-com.pages.dev/agile-yakiniku/","summary":"\u003cp\u003eเมื่อเย็นนี้ผมกับน้องๆในชมรมมีโอกาสไปกินเนื้อย่างมาครับจริงๆแล้วจุดประสงค์ของการไปกินเนื้อย่างครั้งนี้ไม่มีอะไรเลยนอกจากความอยากอยากและอยากที่สั่งสมมานานหลายสัปดาห์ระหว่างที่กินๆอยู่มีน้องคนหนึ่งพูดขึ้นมาว่า \u0026ldquo;\u003cstrong\u003eกินเนื้อย่างนี่มันอไจล์มั้ยพี่\u003c/strong\u003e\u0026rdquo; ซึ่งหลังจากคุยกันในวงเนื้อผมสรุปคร่าวๆได้ว่าการกินเนื้อย่างกับน้องๆหรือเพื่อนมันไม่ต่างอะไรกับการทำโปรเจ็คซอฟท์แวร์เลยครับ\u003c/p\u003e\n\u003cp\u003eเรามามองที่ฝั่งเนื้อย่างก่อน ตอนที่เราเข้ามาในร้านทุกคนจะเลือกตำแหน่งที่จะนั่ง ที่ตัวเองจะกินได้สบายที่สุด บางคนเลือกที่จะนั่งตรงข้ามคนที่กินเก่งที่สุดเพราะ ถ้าอิ่มเมื่อไรมันจะได้กินแทนเรา ในกรณีนีนี้ผมไปกันห้าคน แบ่งกันเป็น 2 เตา ซึ่งน่าจะเดาไม่ยากว่าเตาหนึ่งก็จะมี 2 คนรับผิดชอบเป็นหลัก และมีน้องคนหนึ่งเป็นตัวเสริมอยู่ระหว่าง 2 เตานี้ พอเลือกที่นั่งได้แล้วพนักงานก็จะมารับออเดอร์ซึ่งการกินแบบบุฟเฟ่เราก็สั่งในสิ่งที่เราอยากกิน มากน้อยแล้วแต่ศรัทธา พนักงานก็รับออเดอร์ไป แล้วหลังจากนั้นเราก็รอ ระหว่างนี้เราจะตัดกลับมาที่โปรเจ็คซอฟท์แวร์กันก่อน       \u003cbr\u003e\nในโปรเจ็คซอฟท์แวร์ทีมๆ หนึ่งจะประกอบไปด้วยคนที่เชี่ยวชาญในแต่ละสาขาที่แตกต่างกัน จริงอยู่ที่ \u003cstrong\u003eAgile\u003c/strong\u003e มักจะบอกไว้ว่า \u003cstrong\u003eRole\u003c/strong\u003e ในทีมมันเป็นแค่สิ่งสมมติ แต่ถ้าเรามองในความสามารถจริงๆ ก็จะมีคนที่เชี่ยวชาญแต่ละสาขาอยู่นอกจากนั้นยังมีเรื่องของ Senior กับ Junior อีกซึ่งก็คล้ายๆ กับการที่เราเลือกนั่งตรงข้ามกับคนที่กินเก่งกว่าในเตาเดียวกัน เมื่อเราฟอร์มทีมขึ้นมาได้แล้วสิ่งต่อไปคือรับงานจากลูกค้า ในกรณีนี้มันจะกลับกันเลยขอข้ามกลับไปที่ฝั่งกินเนื้อย่างกันต่อ\u003c/p\u003e\n\u003cp\u003eพอเนื้อที่สั่งมาถึง ซึ่งมันก็มักจะมากันในปริมาณมากๆ พร้อมๆ กันหลายอย่าง ตามที่แต่ละคนสั่งไป ซึ่ง ก็ขึ้นอยู่กับสไตล์ในการกินของแต่ละคนว่าชอบกินอะไรก่อน กินอะไรหลัง หรือบางคน กินอย่างละนิดอย่างละหน่อย ให้รสชาติเปลี่ยนไปเปลี่ยนมาในปาก ก็แล้วแต่สไตล์ ทุกคนจะรับผิดชอบในสิ่งที่ตัวเองสั่งมาในกรณีที่อิ่มแล้ว และเลือกที่จะช่วยกันกินในสิ่งที่คนอื่นกินไม่ไหวแล้ว ถ้ายังไหวอยู่นะ (ซึ่งก็อุดมคติมาก เพราะถ้าอิ่มจริงๆ ก็มักจะเกี่ยงกันหรือในกรณีที่เห็นวันนี้ย่างให้แล้วส่งให้ถึงจานเลย)        \u003cbr\u003e\nเวลาเราเก็บ Requirement จากลูกค้ามา ซึ่งก็สารภาพตามตรงว่าผมก็ไม่เคยเก็บจากลูกค้าจริงๆ เพราะทำแค่โปรเจ็คของปีสี่ แต่สิ่งที่เกิดขึ้นและคล้ายกันคือสไตล์การทำงานมันไม่ต่างอะไรกับสไตล์การกินเลย เราเลือกในสิ่งที่เราชอบทำก่อน (หรือในบางกรณี ทำในสิ่งที่ง่ายกว่าก่อน) ในกรณีเวลาเราทำ \u003cstrong\u003eScrum\u003c/strong\u003e เราต้องทำ \u003cstrong\u003eSprint Planning\u003c/strong\u003e ซึ่งมักจะเลือก Requirement ที่สำคัญที่สุดมาทำก่อนคนเลือกคือใคร คือลูกค้า แต่ในกรณีนี้ลูกค้าคือตัวเองถามว่าจะเลือกอะไร แว็บนี้แหละที่แนวคิดแบบ Scrum มันโผล่เข้ามาและเห้ย มันจริง เราทำมันอยู่ทุกวันแหะ เราเลือกสิ่งที่เราอยากกิน (หรืออยากทำ) มาทีละนิดใส่ลงไปในเตาแต่ละรอบ ไม่ต่างจากการเลือกงานมาทำในแต่ละ Sprint เลย ซึ่งในเตาแรกเนี่ย จะคล้ายๆ เป็นการประเมินว่าในเตาหนึ่งมันวางเนื้อได้สูงสุดกี่ชิ้น รอบต่อไปเราจะกะได้โดยประมาณว่าจะวางได้เท่าไร ไม่ว่าเนื้อนั้นจะมาแบบลูกเต๋า เป็นแผ่น หรือเป็นเนื้อคนละชนิดก็ตาม\u003c/p\u003e","title":"กินเนื้อย่างก็อไจล์"},{"content":"หนึ่งในวิชาบังคับที่ผมต้องเรียนให้ผ่านก่อนจบปี 4 คือวิชาสัมมนาครับเป็นวิชาที่นศในชั้นปีที่ 4 จะต้องแบ่งกลุ่มกันแล้วไปเชิญวิทยากรมาจัดงานสัมมนาหรือพูดง่ายๆมาบรรยายนั่นเองครับโดยในสัปดาห์นี้เป็นความรับผิดชอบของกลุ่มผมกับเพื่อนอีก 10 ชีวิตได้ช่วยกันจัดงานขึ้นมาในเช้าวันนี้ซึ่งวิทยากรก็ไม่ใช่คนที่ไหนไกลก็คือคุณกุลวัฒน์วงศาโรจน์หรือพี่ปอมจากกลุ่ม Agile66 นั่นเองครับ\nระหว่างที่กลุ่มอื่นก็จัดงานสัมมนาไปในช่วง 2 เดือนที่ผ่านมานับว่าผมโชคดีมากที่มีงานสัมมนาเกี่ยวกับ Software จัดขึ้นมาตลอดทุกเดือนไม่ว่าจะเป็นThailand Practical Software Engineering ConferenceและAgile Tour Bangkok 2013ซึ่งนอกจากจะไปหาความรู้มาประดับตัวจากงานแล้วทั้งสองงานยังมีจุดประสงค์แฝงคือการไปทาบทามวิทยากรซึ่งก็คือพี่ปอมทั้งสองงานซึ่งก็น่ายินดีที่พี่ปอมตอบตกลงตั้งแต่ครั้งแรกที่เจอกันเลยซึ่งหลังจากติดต่อกันหลังจากนั้นไม่กี่ครั้งก็ถึงวันงานซึ่งก็คือวันนี้\nระหว่างรอวิทยากรมาทางกลุ่มก็ได้เปิดวิดีโอไปสอบถามกลุ่มตัวอย่างว่า \u0026ldquo;อไจล์คืออัลไล\u0026rdquo; ซึ่งได้ไปถ่ายทำและทำการสอบถามมาในสัปดาห์ก่อนหน้านี้บอกตามตรงว่ารู้สึกดีมากที่ได้เห็นหลายๆคนยิ้มกับความดิบในคลิปโดยไม่ได้ตัดต่อแต่อย่างใดซึ่งอันที่จริงแล้วก็ถือว่าเป็นความผิดพลาดของผมเองเพราะในตอนแรกตั้งใจไว้ว่าจะตัดต่อให้ดูดีเหมือน VRZO แต่ด้วยข้อจำกัดทางเวลารวมถึงติดปัญหานิดหน่อยทำให้สุดท้ายแล้ววิดีโอก็ไม่ได้ตัดไม่ได้ใส่ซับเลยออกมาเป็นไฟล์ดิบๆอย่างที่เห็นในงาน\nโดยส่วนตัวแล้วตั้งแต่เลิกผมเลิกทำกิจกรรมก็แทบจะไม่ได้พูดต่อหน้าคนมากๆอีกเลยวันนี้เป็นอีกหนึ่งวันที่พิสูจน์ว่า \u0026ldquo;ถึงจะซ้อมมาแค่ไหนก็สั่นได้\u0026rdquo; ถึงแม้คนที่มาร่วมจะเป็นเพื่อนร่วมภาคเดียวกันแต่ก็ยังมีน้องๆจากภาควิชาอื่นและก็ยังมีนศ. มาจากคณะอื่นด้วยไม่สั่นก็ไม่รู้จะพูดยังไงแล้วครับพอแนะนำวิทยากรเสร็จก็ปล่อยให้เป็นหน้าที่ของพี่ปอมแล้วครับ\nข้อเสียของการเป็นคนจัดงานคือไม่มีโอกาสจดครับเพราะต้องตั้งใจฟังแล้วก็เป็นหน้าม้าบ้างในบางโอกาสแต่มีคำพูดบางประโยคที่ผมจำได้จากการบรรยายผมอาจจะถ่ายทอดคำพูดไม่ได้เป๊ะๆนะครับแต่ประมาณว่า \u0026ldquo;อไจล์มันเป็นแค่แนวคิดคือจะเอาไป Adapt กับอะไรก็ได้แทบทุกอย่าง\u0026rdquo; ซึ่งผมเห็นด้วยจริงๆมันเหมือน Zen คือเอามาประยุกต์ใช้ได้กับทุกเรื่องแต่ผมนับถือ Agile มากกว่าจริงๆแล้วอาจจะเป็นเพราะผมเป็นคนทำซอฟท์แวร์ด้วยเลยเข้าใจความรู้สึกในความหมายของคำๆนั้นก็อาจจะไม่ผิดนัก\nอีกหนึ่งเรื่องเด่นๆที่ทุกคนเกือบทั้งห้องน่าจะสนใจคือตอนที่พี่ปอมพูดถึงทักษะที่จำเป็นที่สุดของโปรแกรมเมอร์ (ที่ไม่มีใครบอกคุณ) โดยทักษะที่ทุกคนสนใจที่สุดเห็นจะเป็น \u0026ldquo;การตั้งชื่อตัวแปรและเมธอด\u0026rdquo; เพราะไม่มีใครสอนในวิชาโปรแกรมมิ่ง (จริงๆแล้วอาจจะมีแต่พอเขียนจริงๆก็ลืมกัน) ซึ่งก็จะโยงมาหาอีกทักษะหนึ่งก็คือ \u0026ldquo;การทำงานเป็นทีม\u0026rdquo; ครับหลังจากนั้นพี่ปอมก็อธิบาย Agile Manifesto กับอไจล์คืออะไรซึ่งเป็นหนึ่งในเรื่องที่ผมอยากฟังคำอธิบายมากที่สุดในวันนี้แต่น่าเสียดายที่ผมต้องออกไปคุยกับอาจารย์แว็บนึงเลยพลาดจุดนี้ไป\nพอกลับมาจากคุยกับอาจารย์พี่ปอมก็พาเล่น Ball Point Game โดยตอนแรกว่าจะเล่นข้างหน้าหอประชุมแต่เสียงดังมากเลยย้ายกลับมากระจายกันเล่นอยู่ทั่วพื้นสโลป โดยเกมส์นี้จะแบ่งกลุ่มออกเป็นกลุ่มละ 10 คนในที่นี้และเกมนี้มีกฏอยู่ 3 ข้อคือ\nต้องทำการส่งบอลผ่านทุกคนในทีมถึงจะนับเป็น 1 แต้ม ถ้าตกไม่นับ บอลต้องมีการผ่านอากาศคือส่งต่อๆ มือต่อมือไม่ได้ ห้ามส่งให้คนที่นั่งติดกัน โดยจะให้เวลา 2 นาทีแรกในการวางแผนแล้วก็ Estimate ว่าคิดว่ากลุ่มจะทำได้กี่แต้มหลังจากผ่าน 2 นาทีแล้วก็จะเล่นจริง 2 นาทีซึ่งจุดนี้เป็นอะไรที่สนุกมาก (แต่เป็นคนจัดงานก็ไม่ได้เล่นด้วย T^T) ที่เห็นเพื่อนตอนแรกๆงงๆเริ่มที่จะคุยกันเล่นแล้วยิ้มกันหัวเราะกันออกมาเห็นการ Estimation ผิดเห็นแนวคิดการ Retro แบบต่างๆกันแต่ละกลุ่มพัฒนาการและเทคนิคที่ซับซ้อนของแต่ละกลุ่มผมไม่รู้ว่าเพื่อนที่เล่นอยู่สนุกมั้ยแต่ผมรู้สึกดีมากที่ได้เห็นกิจกรรมแบบนี้รู้สึกดีจริงๆบรรยายไม่ถูกเลย\nพอจบเกมพี่ปอมบอกว่าสิ่งที่สังเกตุเห็นที่นี่จริงๆคือ Natural Velocity หมายถึงทีมพอทำงานเต็มที่แล้วเนี่ยนั่งทำอยู่ที่เดิมแต่เปลี่ยนวิธีไปเรื่อยๆพอถึงจัดๆหนึ่งก็จะเป็นจุดที่ทีมทำได้เร็วสุดล่ะ (และจุดนั้นจะ Estimate ได้ใกล้เคียงมากๆด้วย) ซึ่งจากประสบการณ์การทำ Agile มาทีมผมทำได้น้อยถึงน้อยมากเลยในจุดนี้ต้องกลับไปทบทวนจริงๆว่าทีม Inspect \u0026amp; Adapt มากแค่ไหน (ถึงแม้เราจะทำ Retrospective ด้วยแล้วก็ตาม)\nหลังจากนั้นแล้วพี่ปอมก็ได้พูดถึงศัพท์ต่างๆที่พอเราศึกษา Agile น่าจะผ่านหูผ่านตามาบ้างอย่างเช่น Continuous Improvement, Value Driven, Early Feedback (อันนี้ผมชอบมากกับการเปรียบที่ว่าการเขียนโปรแกรมก็เหมือนการดีดกีตาร์ถ้าเราดีดไปแล้วต้องรอ 3 ชม. กว่าเสียงมันจะดังกลับมาคิดว่าเราต้องใช้เวลาเท่าไรในการเรียนดีดกีตาร์), Transparency ที่พูดถึงเรื่อง Trust และพูดถึงเรื่อง Code อีก 2 เรื่องคือ \u0026ldquo;Good code is its own best documentation.\u0026rdquo; และประโยคเด็ดของลุงบ็อบผู้แต่ง Clean Code ที่แปลไทยได้ว่า \u0026ldquo;ถ้าเขียน Comment เมื่อไรรู้ไว้ซะว่า Code แกมันกาก\u0026rdquo; หลังจากนั้นก็ทวน Agile Manifesto อีกรอบแล้วแนะนำผู้ที่จะศึกษาเกี่ยวกับอไจล์ว่าควรจะทำไง (ง่ายก็คืออ่าน) โดยหนังสือที่แนะนำคือ Agile Samurai ซึ่งก็คือเล่มเดียวกับที่ผมชอบแนะนำน้องเวลามาถามเกี่ยวกับ Agile ว่าคืออะไรเพราะมันอ่านง่ายจริงๆโดยเฉพาะฉบับแปลเถื่อนจากเกรียนเพรสที่อุตส่าห์ไปขุดมาจนเจอ\nสุดท้ายนะครับต้องขอบคุณวิทยากรคุณกุลวัฒน์และทีมงานมากๆ นะครับที่สละเวลามาให้ความรู้แก่พวกเรา ขอบคุณเพื่อนๆ ปี 4 ทุกคนนะครับที่มาเข้าสัมมนาในวันนี้, ช่วยกันตอบแบบสอบถามและร่วมกันทำกิจกรรมกันขอบคุณวิทย์ ที่จัดการหาของที่ระลึกให้ รวมถึงเรื่องดูแลวิทยากรด้วยขอบคุณพัด ที่อุตส่าห์หากล้อง ตั้งกล้อง รวมถึงเดินถ่ายรูปทั้งงานขอบคุณฟอร์ซที่คุยกับฝ่ายสถานที่ให้ ตอนที่เราไม่ว่างขอบคุณบอลที่ช่วยติดต่อกับอาจารย์ตี๋ให้ตั้งแต่วันแรกยันวันงานของคุณชาลี ที่ช่วยกันออกแบบโลโก้ให้ออกมาได้สวยขนาดนี้ขอบคุณเฮน โอม บูมที่อุตส่าห์มาแต่เช้ากว่าปกติ แล้วก็ดูแลโต๊ะลงทะเบียนให้ขอบคุณซ้ง ที่ช่วยเดินดูแลกลุ่มที่อยู่ข้างบน แล้วก็ช่วยกันแบกลำโพงไปไว้ข้างนอกด้วย ขอบคุณบิว ที่ช่วยกำกับตอนถ่ายคลิป และช่วยออกไอเดียแปลกๆ\nขอบคุณเพื่อนๆ พี่ๆ น้องๆ ที่ช่วยกันแชร์ประชาสัมพันธ์งานไปในสาขาต่างๆ นะครับ\nขอบคุณเพื่อนๆ พี่ๆ ในทวิตเตอร์ที่ช่วยกันรีทวีตประชาสัมพันธ์ เป็นทวีตที่โดนรีมากที่สุดตั้งแต่เล่นมาเลยสุดท้ายขอบคุณกิจกรรมนี้นะครับ ที่ทำให้ฝันของผมในการเผยแพร่อไจล์ไปสู่คนหมู่มากในลาดกระบังเป็นจริง\nขอบคุณทุกคนอีกครั้งครับขอบคุณจริงๆ\nOriginal post at: https://yothinix.blogspot.com/2014/01/blog-post_7.html\n","permalink":"https://yothinix-com.pages.dev/what-the-heck-is-agile/","summary":"\u003cp\u003eหนึ่งในวิชาบังคับที่ผมต้องเรียนให้ผ่านก่อนจบปี 4 คือวิชาสัมมนาครับเป็นวิชาที่นศในชั้นปีที่ 4 จะต้องแบ่งกลุ่มกันแล้วไปเชิญวิทยากรมาจัดงานสัมมนาหรือพูดง่ายๆมาบรรยายนั่นเองครับโดยในสัปดาห์นี้เป็นความรับผิดชอบของกลุ่มผมกับเพื่อนอีก 10 ชีวิตได้ช่วยกันจัดงานขึ้นมาในเช้าวันนี้ซึ่งวิทยากรก็ไม่ใช่คนที่ไหนไกลก็คือคุณกุลวัฒน์วงศาโรจน์หรือพี่ปอมจากกลุ่ม \u003ca href=\"https://www.facebook.com/groups/agile66/\"\u003eAgile66\u003c/a\u003e นั่นเองครับ\u003c/p\u003e\n\u003cp\u003eระหว่างที่กลุ่มอื่นก็จัดงานสัมมนาไปในช่วง 2 เดือนที่ผ่านมานับว่าผมโชคดีมากที่มีงานสัมมนาเกี่ยวกับ Software จัดขึ้นมาตลอดทุกเดือนไม่ว่าจะเป็น\u003cstrong\u003e\u003ca href=\"/tpse-conference-2013-1-keynote/\"\u003eThailand Practical Software Engineering Conference\u003c/a\u003e\u003c/strong\u003eและ\u003cstrong\u003e\u003ca href=\"/agile-tour-bangkok-2013/\"\u003eAgile Tour Bangkok 2013\u003c/a\u003e\u003c/strong\u003eซึ่งนอกจากจะไปหาความรู้มาประดับตัวจากงานแล้วทั้งสองงานยังมีจุดประสงค์แฝงคือการไปทาบทามวิทยากรซึ่งก็คือพี่ปอมทั้งสองงานซึ่งก็น่ายินดีที่พี่ปอมตอบตกลงตั้งแต่ครั้งแรกที่เจอกันเลยซึ่งหลังจากติดต่อกันหลังจากนั้นไม่กี่ครั้งก็ถึงวันงานซึ่งก็คือวันนี้\u003c/p\u003e\n\u003cp\u003eระหว่างรอวิทยากรมาทางกลุ่มก็ได้เปิดวิดีโอไปสอบถามกลุ่มตัวอย่างว่า \u0026ldquo;\u003cstrong\u003eอไจล์คืออัลไล\u003c/strong\u003e\u0026rdquo; ซึ่งได้ไปถ่ายทำและทำการสอบถามมาในสัปดาห์ก่อนหน้านี้บอกตามตรงว่ารู้สึกดีมากที่ได้เห็นหลายๆคนยิ้มกับความดิบในคลิปโดยไม่ได้ตัดต่อแต่อย่างใดซึ่งอันที่จริงแล้วก็ถือว่าเป็นความผิดพลาดของผมเองเพราะในตอนแรกตั้งใจไว้ว่าจะตัดต่อให้ดูดีเหมือน VRZO แต่ด้วยข้อจำกัดทางเวลารวมถึงติดปัญหานิดหน่อยทำให้สุดท้ายแล้ววิดีโอก็ไม่ได้ตัดไม่ได้ใส่ซับเลยออกมาเป็นไฟล์ดิบๆอย่างที่เห็นในงาน\u003c/p\u003e\n\u003cp\u003eโดยส่วนตัวแล้วตั้งแต่เลิกผมเลิกทำกิจกรรมก็แทบจะไม่ได้พูดต่อหน้าคนมากๆอีกเลยวันนี้เป็นอีกหนึ่งวันที่พิสูจน์ว่า \u0026ldquo;\u003cem\u003eถึงจะซ้อมมาแค่ไหนก็สั่นได้\u003c/em\u003e\u0026rdquo; ถึงแม้คนที่มาร่วมจะเป็นเพื่อนร่วมภาคเดียวกันแต่ก็ยังมีน้องๆจากภาควิชาอื่นและก็ยังมีนศ. มาจากคณะอื่นด้วยไม่สั่นก็ไม่รู้จะพูดยังไงแล้วครับพอแนะนำวิทยากรเสร็จก็ปล่อยให้เป็นหน้าที่ของพี่ปอมแล้วครับ\u003c/p\u003e\n\u003cp\u003eข้อเสียของการเป็นคนจัดงานคือไม่มีโอกาสจดครับเพราะต้องตั้งใจฟังแล้วก็เป็นหน้าม้าบ้างในบางโอกาสแต่มีคำพูดบางประโยคที่ผมจำได้จากการบรรยายผมอาจจะถ่ายทอดคำพูดไม่ได้เป๊ะๆนะครับแต่ประมาณว่า \u0026ldquo;\u003cem\u003eอไจล์มันเป็นแค่แนวคิดคือจะเอาไป Adapt กับอะไรก็ได้แทบทุกอย่าง\u003c/em\u003e\u0026rdquo; ซึ่งผมเห็นด้วยจริงๆมันเหมือน Zen คือเอามาประยุกต์ใช้ได้กับทุกเรื่องแต่ผมนับถือ Agile มากกว่าจริงๆแล้วอาจจะเป็นเพราะผมเป็นคนทำซอฟท์แวร์ด้วยเลยเข้าใจความรู้สึกในความหมายของคำๆนั้นก็อาจจะไม่ผิดนัก\u003c/p\u003e\n\u003cp\u003eอีกหนึ่งเรื่องเด่นๆที่ทุกคนเกือบทั้งห้องน่าจะสนใจคือตอนที่พี่ปอมพูดถึงทักษะที่จำเป็นที่สุดของโปรแกรมเมอร์ (ที่ไม่มีใครบอกคุณ) โดยทักษะที่ทุกคนสนใจที่สุดเห็นจะเป็น \u0026ldquo;\u003cem\u003eการตั้งชื่อตัวแปรและเมธอด\u003c/em\u003e\u0026rdquo; เพราะไม่มีใครสอนในวิชาโปรแกรมมิ่ง (จริงๆแล้วอาจจะมีแต่พอเขียนจริงๆก็ลืมกัน) ซึ่งก็จะโยงมาหาอีกทักษะหนึ่งก็คือ \u0026ldquo;\u003cem\u003eการทำงานเป็นทีม\u003c/em\u003e\u0026rdquo; ครับหลังจากนั้นพี่ปอมก็อธิบาย \u003cstrong\u003eAgile Manifesto\u003c/strong\u003e กับอไจล์คืออะไรซึ่งเป็นหนึ่งในเรื่องที่ผมอยากฟังคำอธิบายมากที่สุดในวันนี้แต่น่าเสียดายที่ผมต้องออกไปคุยกับอาจารย์แว็บนึงเลยพลาดจุดนี้ไป\u003c/p\u003e\n\u003cp\u003eพอกลับมาจากคุยกับอาจารย์พี่ปอมก็พาเล่น \u003cstrong\u003eBall Point Game\u003c/strong\u003e โดยตอนแรกว่าจะเล่นข้างหน้าหอประชุมแต่เสียงดังมากเลยย้ายกลับมากระจายกันเล่นอยู่ทั่วพื้นสโลป โดยเกมส์นี้จะแบ่งกลุ่มออกเป็นกลุ่มละ 10 คนในที่นี้และเกมนี้มีกฏอยู่ 3 ข้อคือ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eต้องทำการส่งบอลผ่านทุกคนในทีมถึงจะนับเป็น 1 แต้ม ถ้าตกไม่นับ\u003c/li\u003e\n\u003cli\u003eบอลต้องมีการผ่านอากาศคือส่งต่อๆ มือต่อมือไม่ได้\u003c/li\u003e\n\u003cli\u003eห้ามส่งให้คนที่นั่งติดกัน\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eโดยจะให้เวลา 2 นาทีแรกในการวางแผนแล้วก็ Estimate ว่าคิดว่ากลุ่มจะทำได้กี่แต้มหลังจากผ่าน 2 นาทีแล้วก็จะเล่นจริง 2 นาทีซึ่งจุดนี้เป็นอะไรที่สนุกมาก (แต่เป็นคนจัดงานก็ไม่ได้เล่นด้วย T^T) ที่เห็นเพื่อนตอนแรกๆงงๆเริ่มที่จะคุยกันเล่นแล้วยิ้มกันหัวเราะกันออกมาเห็นการ Estimation ผิดเห็นแนวคิดการ Retro แบบต่างๆกันแต่ละกลุ่มพัฒนาการและเทคนิคที่ซับซ้อนของแต่ละกลุ่มผมไม่รู้ว่าเพื่อนที่เล่นอยู่สนุกมั้ยแต่ผมรู้สึกดีมากที่ได้เห็นกิจกรรมแบบนี้รู้สึกดีจริงๆบรรยายไม่ถูกเลย\u003c/p\u003e","title":"เติมฝันให้เป็นจริงด้วยอไจล์คืออัลไล"},{"content":"เมื่อประมาณ 6 เดือนที่แล้วมีงาน Event หนึ่งที่เปลี่ยนชีวิตผมไปตลอดกาลงานนั้นคือ Agile Thailand 2013 อย่างที่ผมพูดถึงมาหลายๆครั้งและตลอดหลายเดือนที่ผ่านมาความรู้ความเข้าใจในอไจล์นั้นก็เพิ่มขึ้นตามเวลาเป็นเหมือนขนมที่กินเท่าไรก็ไม่เบื่อ (อย่างน้อยก็ตอนนี้) และกินมาตลอดหลายเดือนด้วยความเอร็ดอร่อยในวันนี้ความรู้สึกหลังจากไปงานAgile Tour Bangkok 2013มาคือผมรู้สึกสดใหม่อีกครั้งผมก็ไม่รู้จะบรรยายยังไงให้เข้าใจว่ามันฟินมากเพื่อไม่ให้เสียเวลาไปมากกว่านี้ข้างล่างคือสรุป Session ที่ผมไปนั่งฟังมาในงานวันนี้ครับ\nSoftware must build for CHANGE not build for LAST เหตุผลที่ผมเข้า Session นี้สารภาพตามตรงว่าเพราะคนพูดครับแฮร่จะว่าเป็นแฟนคลับก็ไม่เชิงซะทีเดียวแต่ผมรู้สึกทุกครั้งหลังจากเข้า Session ของพี่รูฟ+Twin Panichsombatผมมักจะได้ของเล่นและพลังอะไรบางอย่างกลับมาซึ่งทำให้การทำอไจล์นั้นไม่เคยน่าเบื่อเลยครั้งนี้ก็เช่นกันครับของเล่นใหม่ที่ผมได้มามันเรียกว่า Fishbowl ครับ\nFishbowl คือรูปแบบการประชุมที่แหวกจากขนบการประชุมแบบดั้งเดิมโดยจะให้คนที่อยู่ในที่ประชุมทุกคนสามารถเขียนคำถาม/หัวข้อที่ต้องการสนทนาลงในการ์ดซึ่งคนที่ทำหน้าที่เป็นคนจัดก็จะเก็บลงใน Fishbowl จากนั้นเราก็จะทำการสุ่มคำถาม/หัวข้อที่จะสนทนาขึ้นมาพูดกันเป็นเวลา 5 นาทีซึ่งเมื่อหมดก็จะให้ผู้เข้าร่วมทั้งหมดตัดสินว่าเราจะคุยกันต่อ (Like) หรือเราจะไปคุยเรื่องอื่น (Dislike) แต่ส่วนสำคัญอีกส่วนหนึ่งของ Fishbowl ก็คือทุกคนมีสิทธิที่จะพูดหรือตอบในหัวข้อที่เลือกมาได้โดยจะจัดเก้าอี้ไว้ 4-5 ตัวซึ่งจะต้องมีคนที่ร่วมการประชุมใครก็ได้นั่งอยู่แต่เหลือไว้ 1 ที่เพื่อที่จะเปิดโอกาสให้คนที่ไม่ได้อยู่ในวงสนธนา (คนฟัง) มีสิทธิที่จะเข้ามาแสดงความคิดเห็นได้ซึ่งเมื่อมีคนเข้ามา 1 คนก็จะต้องมีคนออกไป 1 คน (ซึ่งดูเหมือนจะมีคนจ้องจะออกตลอด)\nsrc: https://www.scrum-tips.com/agile/stacey-complexity-model/\nนอกจาก Fishbowl แล้ว Session นี้ยังทำให้ผมได้รู้จักกับ Stacey Matrix ซึ่งเป็นกราฟในการประเมินรูปแบบของ Software Project ว่าเราอยู่ในสภาพไหนและเราควรจะใช้ Process อะไรมาจับโดยแบ่งเป็น 3 แกนคือ Requirement, People และ Technology ยกตัวอย่างเช่นถ้า Requirement ของโปรเจ็คเราแทบไม่เปลี่ยนแปลงเลยและ Technology ที่ใช้ก็คาดเดาได้เราก็จะตกอยู่ในโซน Simple ซึ่ง Process ที่แนะนำให้ใช้ก็คงจะเป็น Waterfall นะโดยแต่ละโซนจะมี Process ที่น่าจะรองรับได้เช่น Agile จะอยู่ในโซน Complicated แต่ถ้าไปตกอยู่ในโซน Anarchy ก็บอกได้คำเดียวว่า \u0026ldquo;วอดวาย\u0026rdquo; สุดท้ายพี่รูฟสรุปด้วยประโยคที่ว่า \u0026ldquo;Software is Business, Business is never stop\u0026rdquo; จริงๆมันยาวกว่านี้แต่ผมจำได้แค่นี้ความหมายประมาณว่าขนาดธุรกิจยังไม่เคยหยุดที่จะเปลี่ยนแปลงเลยตัวซอฟท์แวร์ก็เช่นเดียวกันคำถามที่เหลือใน session นี้ผมขอสรุปไว้เป็น bullet ดีกว่าเพราะว่ายังมีอีกหลาย session ให้เขียนต่อนะครับ\nข้อดีของ Agile\nทำให้มุมมองที่มีต่อการสร้าง Software เปลี่ยนไป (มีเอกลักษณ์เฉพาะตัว) กลับไปสู่ความเป็นมนุษย์อีกครั้ง (งานมีแค่เสร็จกับไม่เสร็จไม่มีเสร็จไปกี่เปอร์เซ็นต์)ข้ เสียของ Agile\nทำ Long Estimation ไม่ได้ และยืนยันว่าจะทำตาม Plan ที่วางไว้ไม่ได้ซึ่งทำให้จ่ายเงินแบบโปรเจ็คปกติไม่ได้เช่นเดียวกัน ต้องเผชิญกับความกลัวในการเปลี่ยน Culture ขององค์กร ถ้าอยากทำอาชีพอย่างวิทยากร\nเพิ่งรู้ว่าอาชีพ Coach นี่มันแบ่งเป็น 3 แขนง Organization, Team และ Technical ซึ่งการจะเป็นได้สำคัญคือแค่อ่านหนังสือไม่พอ แต่ต้องทำเป็นด้วย (Lead by example) วิธีรับมือกับ Requirement ที่เปลี่ยนแปลงบ่อย\nทำ Automate ให้มากที่สุดให้เห็นว่าเกิด effect กับส่วนไหนบ้าง มีระบบป้องกันความเสียหายจากความเปลี่ยนแปลงซึ่งการทำ Unit Test และ Continuous Integration ช่วยได้ ต้องสร้าง Environment ที่รองรับการเปลี่ยนแปลงด้วย คำคม: ถ้าทุกอย่างสำคัญหมดแสดงว่าไม่มีอะไรสำคัญเลย Scrumban = Scrum + Kanban: Managing flow in a chaotic world สำหรับ Session นี้คนที่เป็น Speaker นั้นมาจาก Malaysia ครับเลยฟังยากนิดหน่อยโดย Speaker พาเราไปรู้จักหัวใจของ Scrum ก่อน (5 Artifact 3 Role 5 Ceremony 5 Value) หลังจากนั้นจึงพาเราไปรู้จักกับ Kanban ซึ่งประโยคหนึ่งที่กินใจมาก (เพราะตัวเองก็เพิ่งเริ่มทำ Kanban ได้ 2 อาทิตย์กว่าๆ) คือ Kanban is all around us แล้วคุณ Tze ก็ยกตัวอย่างให้ฟังเช่นเวลาคุณไปดูหนังที่โรงหนังตัวคุณนะแหละเป็น Kanban, เวลาคุณไปซื้อกาแฟ Starbuck ตัวแก้วนะแหละคือ Kanban คือทุกอย่างที่กล่าวมามันจะมี Flow ซึ่งก็คือหัวใจของ Kanban นั่นเองนอกจากนั้นยังพูดถึง Push vs Pull ซึ่งใน Kanban เราต้องบอกว่า How much I can do (ซึ่งก็คือ Pull) สุดท้ายของ Kanban คือ Identified and manage constraint ซึ่งถ้าสมมติเป็นท่อน้ำตัว Constraint ก็คือคอขวดนะแหละโดยเราต้องหาวิธียังไงก็ได้ที่จะจัดการกับคอขวดที่เกิดขึ้น\nในส่วนของ Scum + Kanban ซึ่งก็คือหัวข้อหลักที่จะคุยกันวันนี้ผมจับใจความได้สองข้อข้อแรกคือตัวบอร์ดหรือที่เรียกกันว่า Work Stage และตัว WIP Limit ใน Kanban จะเป็นตัวสะท้อนของสิ่งที่ทีมเป็นและคุณค่าในตัวของมันเอง (ไม่รู้ว่าผมเข้าใจตรงนี้ถูกรึเปล่านะ) และการเอา Kanban มารวมกับ Scrum จะเปลี่ยนพฤติกรรมของทีมแทนที่จะสร้าง Task ใหม่ๆขึ้นมาแต่จะเปลี่ยนเป็นส่งมอบ Value แทน\nช่วงถามตอบมีคำถามซึ่งถ้าไม่มีคนถามผมก็ไม่ทันสังเกตุและเป็นสิ่งที่น่าสนใจมากคือในสไลด์บอกว่าในทีมมี Developer 9 คนแต่ทำไมตั้ง WIP ใน In Progress ไว้ 8 แล้วอีกคนทำอะไร ? คุณ Tze ตอบได้น่าสนใจมากว่าอีกคนหนึ่งนั้นมีหน้าที่ในการเดินไปทั่วและสังเกตุงานที่คนอื่นกำลังทำอยู่และเข้าไปช่วยถ้าทำได้ซึ่งจะได้อะไรมากกว่าการนั่งทำงานอยู่คนเดียวแน่นอนซึ่งก็มีคำถามตามมาอีกว่าถ้าไอ 1 คนมันไม่ยอมลุกไปไหนกูจะนั่งเล่น Hayday อยู่ตรงนี้แหละเราจะทำไงคุณ Tze แนะนำถึง Effect ของ Peer power จะมีประโยชน์มากกว่าให้ Manager มาสั่งว่าคุณต้องทำอย่างนั้นอย่างนี้นะในสถานการณ์นี้\nBuilding high performance culture เมื่อวันจันทร์ที่ผ่านมาผมได้ไปร่วมAgile 66 Community Eventมาซึ่งได้เชิญคุณ Henrik Kniberg มาบรรยายเรื่องCultural \u0026gt; Processซึ่งถ้าผมมีโอกาสก็คงจะมาเขียนเกี่ยวกับสิ่งที่ได้รับมาจากงานนั้น (ดองไว้ก่อน) ประเด็นคือในงานนั้นมีคนๆหนึ่งทักผมครับซึ่งผมมาทราบทีหลังว่าคือคุณ Arunthep ซึ่งก็คือ Speaker ของ Session ที่เรากำลังจะมาพูดถึงนี้โดยถ้ามองย้อนกลับไปไม่ว่าจะเป็น Agile Thailand หรือ TPSE ผมก็เห็นชื่อคุณ Arunthep อยู่บ่อยมากแต่ไม่เคยคิดจะเข้าเลยวันนี้เลยนึกครึ้มลองเข้าไปฟังดูและอาทิตย์นี้ดูเหมือนบรรยากาศการสร้าง Culture แทบจะอยู่รอบตัวเราหัวข้อนี้ซึ่งมีคำว่า Culture อยู่จึงล่อลวงผมเข้าไปได้ง่ายขึ้นไปอีก\nตัว Session พูดถึงโครงสร้างของ High Performance Culture ว่าประกอบด้วย 3 องค์ประกอบคือ Human Dynamic, Practices และ Environment (ซึ่ง Agile จัดอยู่ใน Practices นะครับ) หลังจากนั้นก็ตั้งคำถามว่าถ้าเราทำ Software เหมือนเดิมเป๊ะๆเลยเนี่ยเราจะทำได้เร็วขึ้น, เท่าเดิมหรือช้าลงซึ่งก็มีหลากหลายคำตอบมากในห้องแต่สรุปก็คือเร็วขึ้น 60-80% โดยทางวิทยากรพูดถึงลูปซักอย่างที่คล้ายๆกับของ Lean มากแต่ผมจำไม่ได้ว่าชื่ออะไรเป็นตัวอธิบายถึงคำตอบข้างบน ในเรื่องขององค์ประกอบในการสร้าง High Performance Team ทางวิทยากรอธิบายว่าจะประกอบด้วยหลายๆอย่างคือ\nTrust คือการยอมที่จะรับความเสี่ยงและให้โอกาสคนอื่น ต้องขอโทษเป็นและไม่มีการเมืองภายใน โดยได้โยงไปถึง Spiral Trust หรือความจริงของ Trust ว่ามันไม่ได้สร้างยากและเสียไปยากเลย ถ้าเราให้โอกาสคนอื่นและคนอื่นก็ให้โอกาสกับเราเหมือนกัน ยกตัวอย่างเช่น US vs THEM ซึ่งเป็นวัฒนธรรมที่ไม่มีใครได้มีแต่เสียกับศูนย์ (Zero Sum) โดยเราจะพยายามปกป้องตัวเอง (+1 US) และไปโทษคนอื่น (-1 THEM) Commitment อันนี้ยกตัวอย่างง่ายๆ คือเราต้องกล้าที่จะบอกว่าทำได้หรือทำไม่ได้ (ไม่ใช่ YES หมด (อันนี้ใน REWORK พูดถึงด้วย)) และยังมีวิธี Fixing breaking commitment เป็นสเตปดังต่อไปนี้- ยอมรับตามตรงว่าทำไม่ได้- ขอโทษ- จะทำอะไรให้มันดีขึ้นบ้าง- ครั้งต่อไปจะไม่เกิดขึ้นอีก Accountability อันนี้จะกลับกันกับ Commitment ซึ่งผมคิดว่าทางวิทยากรได้พูดไว้ในเรื่อง Personal Response Pyramid นะครับ ซึ่งผมก็หาภาพที่ตรงกับ Slide ไม่ได้แต่จะไล่จากฐานพีระมิดคือ Self -\u0026gt; Clarity -\u0026gt; Ask -\u0026gt; Agree -\u0026gt; Call Common Goal หัวข้อนี้คงไม่ต้องอธิบายอะไรมาก Conflict เป็นอะไรที่แปลกมากแต่ผมก็คิดว่าจริงคือ ทีมที่ดีคือทีมที่ทะเลาะกัน (เพราะถ้ามันไม่พูดกันนั่นก็เกินเยียวยาแล้ว) ถ้านั้นยังไม่เห็นภาพทางวิทยากรให้ทุกคนในห้องจับคู่กันแล้วมองตากันโดยไม่ต้องพูด 1 นาทีหลังจากนั้นแล้วถามความรู้สึก ซึ่งหลายคนก็รู้สึกตรงกันว่า แม่งฮามาก แต่วิทยากรก็อธิบายว่ามนุษย์เรามักจะเลี่ยงที่จะเผชิญหน้ากันเสมอ ซึ่งถ้าเราจัดการข้อจำกัดข้อนี้ไปได้ จะทำให้การแก้ปัญหาความขัดแย้งมันง่ายขึ้น หลังจากนี้เป็นพักเที่ยงครับซึ่งบุฟเฟ่อร่อยมากไม่รู้จะบรรยายยังไงไปดูรูปที่เพจAgile Tour Bangkokก็คงจะเข้าใจมากขึ้นนะครับ\nNo Reuse Before Use Session แรกตอนบ่ายนี่เลือกยากระดับนึงเลยครับแต่ผมก็ตัดสินใจเข้า Session นี้ซึ่งผมจัดให้เป็น Session ที่ฮาที่สุดของงานนี้แล้ว (แม้จะฟังออกบ้างไม่ออกบ้าง) โดยคุณ Terry Yin มาเล่าให้เราฟังเรื่อง Software Reuse ซึ่งเป็น Term ที่ผมได้ยินมาบ่อยมากแต่ไม่เข้าใจว่ามันคืออะไรแต่พี่แกเล่นตัดบทโดยบอกว่าเราจะมาพูดถึง Software Use แทน\nวิทยากรเริ่มพาเราจินตนาการไปกับผังเมือง Brazilia เมืองหลวงของประเทศ Brazil ซึ่งเพิ่งรู้ว่านอกจากจะออกแบบเพื่ออนาคตเมื่อกว่า 60 ปีที่แล้วเองนั้นตัวเมืองยังออกแบบให้เป็นรูปเหมือนนกอินทรีและที่สำคัญไม่มีไฟแดงครับ !! แต่ปัญหาก็คือในอนาคตที่คนออกแบบผังเมืองมองไว้นั้นไม่มีคนเดินถนน (Pedestrian) ครับเพราะเขาสันนิษฐานว่าคนในอนาคตคงใช้รถกันหมดทุกคนแล้วซึ่งปัจจุบันมันเกิดสิ่งนี้ขึ้นครับ\nสิ่งที่เกิดขึ้นคือมันมีคนเดินถนนครับแล้วคนเหล่านั้นได้สร้างเส้นทางที่เห็นดังภาพข้างบนขึ้นกลางเมืองซึ่งการที่คนจะข้ามจากทุ่งฝั่งนึงไปอีกฝั่งนึงได้ต้องผ่านถนน 6 เลนย้ำอีกที 6 เลนนะครับซึ่งเสี่ยงชีวิตโคตรๆเลยซึ่งสอดคล้องกับสถิติคือคนบราซิลจะเสียชีวิตจากอุบัติเหตุทางถนนประมาณ 10,000 คนทุกปีซึ่งถ้าคนออกแบบผังเมืองรู้ว่าในอนาคตยังมีคนเดินถนนอยู่คำถามคือมันจะเกิดอะไรขึ้นบ้าง\nจากเรื่องข้างบนพาเราย้อนกลับมาถึง Software Reuse ซึ่งเกิดคำถามขึ้นว่าเราจะรู้ได้ไงว่าส่วนไหนควรจะ Reuse ถ้าเรายังไม่ Use มันด้วยซ้ำวิทยากรพูดถึง Duplication หรือการทำซ้ำว่าเป็น Root of all evil in Software และการ Refactoring นั้นควรจะทำก็ต่อเมื่อสิ่งที่เราเขียนลงไปนั้นมันทำงานได้แล้วไม่ใช่ทำก่อนซึ่งจะทำให้การ Refactoring เป็นการเปลี่ยนแปลงตัว Structure ภายในส่วนนั้นไม่ใช่เปลี่ยน Output ที่ออกมาแต่ถ้าเราเขียนทุกอย่างตามหลักการ Once and only once ปัญหาพวกนี้ก็จะเกิดขึ้นน้อยลงจริงๆแล้วยังมีอีกหลายเรื่องใน Session นี้แต่ผมจับใจความไม่ได้เลยขอทิ้งท้ายด้วยประโยคที่ว่า \u0026ldquo;Design from perspective of use ratherthan implementation\u0026rdquo; ครับ\nBuilding Software Development Culture for Any Scale ผมสังเกตุเห็นสิ่งหนึ่งที่เกิดขึ้นตลอดสัปดาห์ที่ผ่านมาคือมีคนพูดถึงเรื่อง Culture ในองค์กรเยอะมากๆในวันนี้มีถึง 2 Session เลยซึ่งสารภาพตามตรงว่าผมมา Session นี้เพราะโดนกล่อมครับฮ่าพอดีตอนเที่ยงได้มีโอกาสสนทนากับพี่แอมป์+Tanawat Tassanaรวมถึงที่พี่แกมาโฆษณาใน Session ตอนเช้าด้วยเลยตัดสินใจไม่ดู Real Agile#2 ละ (ซึ่งโชคดีมากเพราะ Session นั้นมีคนอัดวิดีโอไว้ที่ \u0026raquo; http://www.youtube.com/watch?v=zWIALP-vqEk)\nSession นี้เริ่มด้วยคำถามว่าทำไมถึงต้องมี Culture โดยยกตัวอย่างสมาชิกใหม่ที่เข้ามาทำงานในทีมว่าเขาไม่ได้เรียนรู้จากกฏแต่เรียนรู้จาก Culture ที่มีอยู่เช่นถ้ามีคนบ่นเกี่ยวกับกฏสักพักเดี๋ยวก็มีคนบ่นตามเป็นต้นคำถามต่อมาคืออะไรคือ Culture คำตอบคือCulture = set of mindsetsทีนี้มันก็จะเกิดคำถามแล้วว่าแล้วกฏหล่ะปรากฏว่า Rules มันคือ Set of behaviors ครับคือรูปแบบพฤติกรรมที่กำหนดมาซึ่งกำหนดได้แค่พฤติกรรมครับแต่ในใจนั้นอีกเรื่องซึ่งทั้งสองอย่างทั้ง Culture และ Rules ต่างมุ่งไปที่เป้าหมายสุดท้ายเดียวกันคือ Bahaviors นี่แหละครับ\nทีนี้เนี่ยเราจะทำวัฒนธรรมที่เราสร้างให้มันเข้มแข็งได้อย่างไรมี 2 ข้อครับข้อแรกคือต้องเปิดรับการเปลี่ยนแปลง (คล้ายๆ Agile แหะ) เพื่อที่จะพัฒนาตัวมันเองรวมถึงต่อต้านความเปลี่ยนแปลงอะไรก็ตามที่ทำให้เกิดผลเสียต่อมันข้อสองพูดถึง Self-Selecting อารมณ์จะประมาณ Natural selection คือแน่นอนว่าไม่ใช่ทุกคนที่จะเห็นคล้อยไปตามวัฒนธรรมที่เกิดขึ้นซึ่งเมื่อส่วนน้อยเห็นไม่ตรงกับส่วนใหญ่เขาก็มีทางเลือกอยู่หลายทางจะทนอยู่, จะสู้หรือจะออกไปประมาณนั้นครับ\nพอพูดถึง How หรือการสร้างวัฒนธรรมให้เกิดขึ้นได้อย่างไรสิ่งสำคัญคือสภาพแวดล้อมครับเพราะสภาพแวดล้อมสามารถส่งเสริมให้พฤติกรรมมันเติบโตได้ (ถ้าดูสไลด์ในส่วนนี้คือต้นไม้ที่มีโครงครับ) ซึ่งก็เกิดคำถามว่าแล้วถ้าสภาพแวดล้อมไม่ดีมันเป็นไงก็เหมือนต้นไม้โตโดยเอากระถางครอบข้างบนมันครับมันโตก็จริงแต่โตได้แค่ในกระถางที่ครอบมันอยู่และในข้อนี้ยังทิ้งท้ายโดยเตือนไว้อีกว่า \u0026ldquo;ถ้าหากเราไม่สร้างวัฒนธรรมของเราขึ้นมาแล้วก็จะมีใครซักคนสร้างมันขึ้นมาแทน\u0026rdquo;\nในส่วนสุดท้ายพูดถึงGood Software Development Cultureที่พี่เขาแนะนำโดยสามารถไปดูได้ในสไลด์ที่แปะลิงค์ไว้ข้างล่างนะครับแต่ข้อที่ผมชอบที่สุดคือIntegrityหรือการซื่อสัตย์กับตัวเองต้องยอมรับผิดถ้าเราผิดไม่ใช่แถให้ตัวเองชนะโดยหนีเหตุผลที่เรายืนหยัดเพื่อมันในตอนแรกCross Pollenationซึ่งก็คือสิ่งที่ผมคิดว่าตัวเองทำอยู่บ่อยๆคือหาของเล่นใหม่ๆที่เห็นคนอื่นทำแล้วดีมาทำกับทีมตัวเองบ้างและสุดท้ายFocus on GOAL not SOLUTIONอันนี้โดนทีมจังๆเลย\n(ลิงค์สไลด์ \u0026raquo; http://slid.es/amptanawat/building-sw-dev-culture-for-any-scale)\nIntroduction to Scrum (A.K.A Agile 101) หลังเบรคสำหรับ Session สุดท้ายนี่ผมไม่รู้จริงๆครับว่าจะเข้า Session ไหนคือเดินไปเหลือบมันทุกห้องจนมาหยุดที่ห้องนี้ (ซึ่งตอนแรกไม่มีในตาราง) สิ่งที่ผมได้รับจาก Session นี้ส่วนใหญ่เป็นสิ่งที่รู้หรือคิดว่าตัวเองรู้อยู่แล้วทั้ง Agile Manifesto, Agile Principle, Scrum, Kanban ฯลฯจึงไม่ได้จดอะไรเลยแต่ Session นี้ทำให้ผมคิดอะไรได้อย่างนึงคือในหลายๆครั้งเราก็ควรยกหัวโขนว่าตัวเองรู้อยู่แล้ววางไว้หน้าห้องแล้วทำตัวเป็นมือใหม่ไม่รู้อะไรเลยจะทำให้เรามองอะไรได้ชัดเจนยิ่งขึ้นและเปิดโอกาสให้เราได้เก็บเกี่ยวในสิ่งที่เราไม่เคยคิดว่ามันมีอยู่กลับมาด้วย\nPanel-Discussion หลังจากจบทุก Session สุดท้ายแล้ว Panel Discussion ซึ่งคราวนี้คือการทำ Fishbowl กันอีกรอบแต่รอบนี้ดีกว่ารอบใน Session เพราะได้เห็นกรณี dislike ชัดเจนกว่าส่วนเรื่องที่สนธนาก็เป็นคำถามที่หลากหลายมากและผมมัวแต่ฟังแบบฟินๆเลยไม่ได้จดอะไรมาเลย\nConclusion สุดท้ายขอบคุณAgile66ที่จัดงานดีๆอย่างนี้ถึงแม้เป้าหมายที่ผมตั้งไว้ให้ตัวเองคือรู้จักคนใหม่ๆเพิ่มขึ้นมันจะไม่สำเร็จแต่อย่างน้อยผมก็ได้สนทนากับคน 2-3 คนซึ่งดีขึ้นกว่างานที่แล้วที่แทบไม่ได้คุยกับใครเลย (เพราะไปคนเดียวด้วยส่วนนึง) น่าเสียดายที่ Session หนึ่งมีเวลาแค่ 45 นาทีเพราะรู้สึกว่ามันจบเร็วเกินไปหลายๆอันยังค้างคา (แต่ก็ยังดีกว่า Barcamp ที่มีแค่ 30 นาที)\nปล.วันนี้เป็นครั้งแรกนับตั้งแต่ฝึกงานที่ได้ลง BTS เพลินจิตเรื่องเล็กๆแต่ความทรงจำไหลหลั่งมาเต็มๆ\nOriginal post at: https://yothinix.blogspot.com/2013/12/agile-tour-bangkok-2013.html\n","permalink":"https://yothinix-com.pages.dev/agile-tour-bangkok-2013/","summary":"\u003cp\u003eเมื่อประมาณ 6 เดือนที่แล้วมีงาน Event หนึ่งที่เปลี่ยนชีวิตผมไปตลอดกาลงานนั้นคือ Agile Thailand 2013 อย่างที่ผมพูดถึงมาหลายๆครั้งและตลอดหลายเดือนที่ผ่านมาความรู้ความเข้าใจในอไจล์นั้นก็เพิ่มขึ้นตามเวลาเป็นเหมือนขนมที่กินเท่าไรก็ไม่เบื่อ (อย่างน้อยก็ตอนนี้) และกินมาตลอดหลายเดือนด้วยความเอร็ดอร่อยในวันนี้ความรู้สึกหลังจากไปงาน\u003ca href=\"http://agiletourbangkok2013thailand.sched.org/\"\u003eAgile Tour Bangkok 2013\u003c/a\u003eมาคือผมรู้สึกสดใหม่อีกครั้งผมก็ไม่รู้จะบรรยายยังไงให้เข้าใจว่ามันฟินมากเพื่อไม่ให้เสียเวลาไปมากกว่านี้ข้างล่างคือสรุป Session ที่ผมไปนั่งฟังมาในงานวันนี้ครับ\u003c/p\u003e\n\u003ch1 id=\"software-must-build-for-change-not-build-for-last\"\u003eSoftware must build for CHANGE not build for LAST\u003c/h1\u003e\n\u003cp\u003eเหตุผลที่ผมเข้า Session นี้สารภาพตามตรงว่าเพราะคนพูดครับแฮร่จะว่าเป็นแฟนคลับก็ไม่เชิงซะทีเดียวแต่ผมรู้สึกทุกครั้งหลังจากเข้า Session ของพี่รูฟ\u003ca href=\"http://plus.google.com/103054764182433148733\"\u003e+Twin Panichsombat\u003c/a\u003eผมมักจะได้ของเล่นและพลังอะไรบางอย่างกลับมาซึ่งทำให้การทำอไจล์นั้นไม่เคยน่าเบื่อเลยครั้งนี้ก็เช่นกันครับของเล่นใหม่ที่ผมได้มามันเรียกว่า Fishbowl ครับ\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eFishbowl\u003c/strong\u003e คือรูปแบบการประชุมที่แหวกจากขนบการประชุมแบบดั้งเดิมโดยจะให้คนที่อยู่ในที่ประชุมทุกคนสามารถเขียนคำถาม/หัวข้อที่ต้องการสนทนาลงในการ์ดซึ่งคนที่ทำหน้าที่เป็นคนจัดก็จะเก็บลงใน Fishbowl จากนั้นเราก็จะทำการสุ่มคำถาม/หัวข้อที่จะสนทนาขึ้นมาพูดกันเป็นเวลา 5 นาทีซึ่งเมื่อหมดก็จะให้ผู้เข้าร่วมทั้งหมดตัดสินว่าเราจะคุยกันต่อ (Like) หรือเราจะไปคุยเรื่องอื่น (Dislike) แต่ส่วนสำคัญอีกส่วนหนึ่งของ Fishbowl ก็คือทุกคนมีสิทธิที่จะพูดหรือตอบในหัวข้อที่เลือกมาได้โดยจะจัดเก้าอี้ไว้ 4-5 ตัวซึ่งจะต้องมีคนที่ร่วมการประชุมใครก็ได้นั่งอยู่แต่เหลือไว้ 1 ที่เพื่อที่จะเปิดโอกาสให้คนที่ไม่ได้อยู่ในวงสนธนา (คนฟัง) มีสิทธิที่จะเข้ามาแสดงความคิดเห็นได้ซึ่งเมื่อมีคนเข้ามา 1 คนก็จะต้องมีคนออกไป 1 คน (ซึ่งดูเหมือนจะมีคนจ้องจะออกตลอด)\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/agile-tour-bangkok-2013/Simple-vs-Complicated-vs-Complex-vs-Chaotic-2-pi_hu_ca7489a7db39b0ac.webp\"\n       srcset=\"/agile-tour-bangkok-2013/Simple-vs-Complicated-vs-Complex-vs-Chaotic-2-pi_hu_ca7489a7db39b0ac.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"354\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003esrc: \u003ca href=\"https://www.scrum-tips.com/agile/stacey-complexity-model/\"\u003ehttps://www.scrum-tips.com/agile/stacey-complexity-model/\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eนอกจาก Fishbowl แล้ว Session นี้ยังทำให้ผมได้รู้จักกับ Stacey Matrix ซึ่งเป็นกราฟในการประเมินรูปแบบของ Software Project ว่าเราอยู่ในสภาพไหนและเราควรจะใช้ Process อะไรมาจับโดยแบ่งเป็น 3 แกนคือ Requirement, People และ Technology ยกตัวอย่างเช่นถ้า Requirement ของโปรเจ็คเราแทบไม่เปลี่ยนแปลงเลยและ Technology ที่ใช้ก็คาดเดาได้เราก็จะตกอยู่ในโซน Simple ซึ่ง Process ที่แนะนำให้ใช้ก็คงจะเป็น Waterfall นะโดยแต่ละโซนจะมี Process ที่น่าจะรองรับได้เช่น Agile จะอยู่ในโซน Complicated แต่ถ้าไปตกอยู่ในโซน Anarchy ก็บอกได้คำเดียวว่า \u0026ldquo;\u003cstrong\u003eวอดวาย\u003c/strong\u003e\u0026rdquo; สุดท้ายพี่รูฟสรุปด้วยประโยคที่ว่า \u0026ldquo;\u003cem\u003eSoftware is Business, Business is never stop\u003c/em\u003e\u0026rdquo; จริงๆมันยาวกว่านี้แต่ผมจำได้แค่นี้ความหมายประมาณว่าขนาดธุรกิจยังไม่เคยหยุดที่จะเปลี่ยนแปลงเลยตัวซอฟท์แวร์ก็เช่นเดียวกันคำถามที่เหลือใน session นี้ผมขอสรุปไว้เป็น bullet ดีกว่าเพราะว่ายังมีอีกหลาย session ให้เขียนต่อนะครับ\u003c/p\u003e","title":"AGILE TOUR BANGKOK 2013 :: งานรวมพล คนอไจล์ ส่งท้ายปี"},{"content":"เอนทรี่นี้ถ้าจะให้พูดตามตรงก็เหมือนภาคต่อของTDE\u0026amp;W (3) :: Team Foundation Serviceเลยทีเดียวเพราะในเอนทรี่ดังกล่าวผมทิ้งท้ายไว้ว่าปัจจุบันผมไม่ได้ใช้ TFS แล้วอย่างไรก็ตามเอนทรี่นี้ก็ไม่ใช่สิ่งที่ผมตั้งใจจะเขียนแต่แรกเพราะผมอยากจะพูดถึง Process ด้วยเพียงแต่ว่าวัฒนธรรมของเราที่ AdWise ยังคงมีวิวัฒนาการอย่างต่อเนื่อง, เปลี่ยนแปลงและเพิ่มขึ้นอย่างมากในช่วง 2 เดือนที่ผ่านมาทำให้ผมคิดว่าเรื่องกระบวนการทำงานผมรอให้ใกล้ๆจบ Project II ค่อยพูดถึงน่าจะดีกว่าวันนี้เราจะมาพูดถึงบอร์ดกันครับ\nสมัยตอนท้าย Project I เป็นช่วงที่เราเริ่มจะจริงจังกับการทำ Scrum เป็นอย่างมากและหนึ่งในเครื่องมือที่ช่วยให้เราทำ Scrum ได้ประสบความสำเร็จในระดับหนึ่งโดยจะไม่พูดถึงไม่ได้เลยก็คือ TFS ซึ่งหน้าตาก็เป็นดังรูปที่แปะอยู่ข้างล่างนี้แหละครับ\nเสียดายไม่เคยแคปหน้าจอไว้ตอนทำงานแต่ก็จะหน้าตาประมาณนี้ทีนี้เนี่ยพอปิดเทอมไปเราก็ไปพัฒนา Technical Skill แยกกันไปซะส่วนใหญ่และยังไม่มีการใช้บอร์ดร่วมกันเลยเป็นโอกาสที่ผมได้ทดลองหาเครื่องมือใหม่ๆหลายตัวอีกครั้งแต่ไม่ว่าผมจะพยายามหาเพียงแค่ไหนมันก็ยังสนองความต้องการไม่ได้ผมต้องการเพียงแค่บอร์ดง่ายๆที่สามารถเอาไว้ดูงานได้ไม่ต้องมีฟีเจอร์หรูหรายุ่งยากซึ่งในที่สุดผมก็กลับมาสู่จุดเริ่มต้นที่ผมทำ Agile นั้นคือEidosครับ\nตัว Eidos เองเนี่ยตอนใช้แรกๆผมแฮปปี้กับมันมากครับมีฟีเจอร์แค่บอร์ด, ตัวจัดการ Backlog แล้วก็ Burndown ซึ่งเพียงพอกับความต้องการแล้วดูเหมือนจะมีความสุขใช่มั้ยครับไม่ครับผมประสบปัญหากับการลากแล้วค้างบ่อยมาก (วิธีแก้คือกด Refresh แล้วลากใหม่) ซึ่งแรกๆก็ทนใช้ได้ครับแต่นานๆไปมันเป็นปัญหาเกินไปแล้วนะผมเลยตัดสินใจเราต้องเปลี่ยนแล้วกระบวนการค้นหาจึงเริ่มต้นขึ้นอีกครั้งแต่ก็เหมือนครั้งที่แล้วไม่ว่าเราพยายามจะค้นหาแค่ไหนเราก็ไม่เคยเจอกับสิ่งที่ตรงกับที่เราต้องการจริงๆ (รอบนี้รู้สึกจะลองJIRAด้วยยิ่งใช้ยากหนักขึ้นไปอีก) สุดท้ายครับเราตัดสินใจกลับคืนสู่สามัญสู่จุดเริ่มต้นที่เราเคยได้ลองเพียงน้อยนิดและประสบความล้มเหลวกับ Project ก่อนหน้าไปและเราไม่ได้ใช้มันอีกเลยเรากลับมาลองมันอีกครั้งนั่นคือจุดเริ่มต้นที่เรากลับมาใช้Physical Board ครับ\nจริงๆแล้วบอร์ดในภาพข้างบนไม่ใช่บอร์ดแบบแรกที่ทีมผมเอากลับมาใช้นะครับเนื่องจากตอนนั้นยังทำ Scrum กันอยู่ยังมี Sprint บลาๆเพราะฉะนั้นแล้วเนี่ยโครงสร้างบอร์ดจะมีรายละเอียดหลายๆอย่างมากกว่านี้ครับแต่หลังได้มีโอกาสไปฟังLean/Kanban Going beyond Scrumที่งานTPSEทำให้ผมเกิดไอเดียหลายๆอย่างครับสิ่งสำคัญก็คือ Scrum เยอะไปสำหรับทีมเราข้อเท็จจริงที่สำคัญที่สุดคือทีมเราต้องเรียนไปด้วยทำ Project ไปด้วยปัญหาที่เราเจอมาตลอดตั้งแต่เริ่มทำ Scrum และยังแก้ไม่ได้เลยก็คือเราไม่เคยส่งงานได้ครบทุกอย่างตามที่เราแบ่งไว้ในแต่ละ Sprint เลยกรณีดีสุดก็ยังเหลือซัก 1-2 งานเสมอซึ่ง Kanban ตอบโจทย์ข้อนี้ได้ครับเพราะมีกฏแค่ 3 ข้อ (ผมคงไม่ลงรายละเอียดนะครับ) แต่เราก็ยังมีกรอบที่เราต้องทำอยู่คือเราจำเป็นต้อง Release งานออกมาให้ได้ภายในทุกอาทิตย์ตาม Requirement ของอ.ที่ปรึกษาของทีมเราซึ่งการทำแบบนี้มันดียังไงพูดง่ายๆก็คือตั้งแต่เปลี่ยนมาใช้ Kanban ผมและทีมไม่เคยกังวลเกี่ยวกับ Task ที่ค้างเกินอาทิตย์อีกเลย (หรืออย่างน้อยก็กังวลน้อยลง) เพราะยังไงมันก็เป็น Flow ไหลไปเรื่อยๆของมันและนอกจากนั้นแล้วการที่เราหันไปดูบอร์ดแทนที่จะเปิดเว็บขึ้นมาลากๆรวมถึงความสะใจในการย้ายงานจาก Todo ไปจนถึง Done นั้นมันเป็นอะไรที่ฟินมากและเราส่งงานได้ต่อเนื่องขึ้นอย่างเห็นได้ชัดนั่นทำให้ผมมีเวลาทดลองอะไรบางอย่างดังรูปที่อยู่ข้างล่างนี้ครับ\nช่วงเวลาประมาณ 2 สัปดาห์ที่แล้วเป็นช่วงที่การเมืองอยู่ในภาวะ Unstable อย่างที่รู้กันแล้วทีมผมจากที่เคยรวมตัวกันทำงานอยู่ใน Office เดียวกันเลยได้โอกาสแยก (เนื่องจากมหาวิทยาลัยประกาศปิดแล้วตรงกับวันพ่อเลยหยุดยาวเลย) ผมเลยทำการทดลองกลับมาใช้บอร์ดอิเล็กอีกครั้งระหว่างที่เราไม่ได้นั่งอยู่ใน Office เดียวกันเป็นเวลาเกือบ 1 สัปดาห์และทำRetrospectiveหลังจากนั้นได้ผลดังต่อไปนี้ครับ\nสรุปก็คือทีมชอบบอร์ดติดผนังมากกว่าในจอคอมครับแต่ข้อดีข้อเสียก็อย่างที่เห็นในรูปคือเราต้องอยู่ที่ Office เดียวกันถึงจะอัพเดทบอร์ดได้และอีกข้อที่ไม่ได้กล่าวในนี้คือเราทำ Estimation ลำบากมาก (จริงๆแล้วต้องบอกว่าขี้เกียจมากกว่า) เพราะต้องมาคอยพล็อตจุดในกราฟวันต่อวันๆ (ซึ่งในปัจจุบันเราก็แทบไม่ได้ทำเลยถึงแม้จะมีข้อมูลตลอดก็ตาม) ในตอนจบก่อนที่เราจะมาถึงปัจจุบันมีข้อสรุปว่าตัวบอร์ดที่แอบๆที่มุมกระดานมันไม่เพียงพอต่อปริมาณงานที่เพิ่มขึ้นเสียแล้วเราเลยตัดสินใจทำบอร์ดใหม่แยกมาจากกระดาน (เพื่อจะได้เอาไว้ทำอะไรได้มากขึ้น) ออกมาเป็นบอร์ดที่เห็นตามรูปบนสุดนั่นแหละครับซึ่งไม่แน่ว่าในอนาคตเราอาจจะเปลี่ยนแปลงไปอีกก็เป็นได้ดังคำกล่าวที่ว่า\nทีมที่มีชีวิตต้องมีวิวัฒนาการ\nแล้วเจอกันใหม่เอนทรี่หน้าสวัสดีครับ\nOriginal post at: https://yothinix.blogspot.com/2013/12/adwise.html\n","permalink":"https://yothinix-com.pages.dev/evolution-of-agile-board-at-adwise/","summary":"\u003cp\u003eเอนทรี่นี้ถ้าจะให้พูดตามตรงก็เหมือนภาคต่อของ\u003ca href=\"/tde-w-3-team-foundation-service/\"\u003eTDE\u0026amp;W (3) :: Team Foundation Service\u003c/a\u003eเลยทีเดียวเพราะในเอนทรี่ดังกล่าวผมทิ้งท้ายไว้ว่าปัจจุบันผมไม่ได้ใช้ TFS แล้วอย่างไรก็ตามเอนทรี่นี้ก็ไม่ใช่สิ่งที่ผมตั้งใจจะเขียนแต่แรกเพราะผมอยากจะพูดถึง Process ด้วยเพียงแต่ว่าวัฒนธรรมของเราที่ AdWise ยังคงมีวิวัฒนาการอย่างต่อเนื่อง, เปลี่ยนแปลงและเพิ่มขึ้นอย่างมากในช่วง 2 เดือนที่ผ่านมาทำให้ผมคิดว่าเรื่องกระบวนการทำงานผมรอให้ใกล้ๆจบ Project II ค่อยพูดถึงน่าจะดีกว่าวันนี้เราจะมาพูดถึงบอร์ดกันครับ\u003c/p\u003e\n\u003cp\u003eสมัยตอนท้าย Project I เป็นช่วงที่เราเริ่มจะจริงจังกับการทำ Scrum เป็นอย่างมากและหนึ่งในเครื่องมือที่ช่วยให้เราทำ Scrum ได้ประสบความสำเร็จในระดับหนึ่งโดยจะไม่พูดถึงไม่ได้เลยก็คือ TFS ซึ่งหน้าตาก็เป็นดังรูปที่แปะอยู่ข้างล่างนี้แหละครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/evolution-of-agile-board-at-adwise/TFS_hu_befb50dba623d7c3.webp\"\n       srcset=\"/evolution-of-agile-board-at-adwise/TFS_hu_7991de20db0b3ea2.webp 480w, /evolution-of-agile-board-at-adwise/TFS_hu_befb50dba623d7c3.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"451\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eเสียดายไม่เคยแคปหน้าจอไว้ตอนทำงานแต่ก็จะหน้าตาประมาณนี้ทีนี้เนี่ยพอปิดเทอมไปเราก็ไปพัฒนา Technical Skill แยกกันไปซะส่วนใหญ่และยังไม่มีการใช้บอร์ดร่วมกันเลยเป็นโอกาสที่ผมได้ทดลองหาเครื่องมือใหม่ๆหลายตัวอีกครั้งแต่ไม่ว่าผมจะพยายามหาเพียงแค่ไหนมันก็ยังสนองความต้องการไม่ได้ผมต้องการเพียงแค่บอร์ดง่ายๆที่สามารถเอาไว้ดูงานได้ไม่ต้องมีฟีเจอร์หรูหรายุ่งยากซึ่งในที่สุดผมก็กลับมาสู่จุดเริ่มต้นที่ผมทำ Agile นั้นคือ\u003ca href=\"http://theeidos.com/\"\u003e\u003cstrong\u003eEidos\u003c/strong\u003e\u003c/a\u003eครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/evolution-of-agile-board-at-adwise/Eidos_hu_790ccb4167d2324e.webp\"\n       srcset=\"/evolution-of-agile-board-at-adwise/Eidos_hu_986f2b00a78d1a39.webp 480w, /evolution-of-agile-board-at-adwise/Eidos_hu_790ccb4167d2324e.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"454\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eตัว Eidos เองเนี่ยตอนใช้แรกๆผมแฮปปี้กับมันมากครับมีฟีเจอร์แค่บอร์ด, ตัวจัดการ Backlog แล้วก็ Burndown ซึ่งเพียงพอกับความต้องการแล้วดูเหมือนจะมีความสุขใช่มั้ยครับไม่ครับผมประสบปัญหากับการลากแล้วค้างบ่อยมาก (วิธีแก้คือกด Refresh แล้วลากใหม่) ซึ่งแรกๆก็ทนใช้ได้ครับแต่นานๆไปมันเป็นปัญหาเกินไปแล้วนะผมเลยตัดสินใจเราต้องเปลี่ยนแล้วกระบวนการค้นหาจึงเริ่มต้นขึ้นอีกครั้งแต่ก็เหมือนครั้งที่แล้วไม่ว่าเราพยายามจะค้นหาแค่ไหนเราก็ไม่เคยเจอกับสิ่งที่ตรงกับที่เราต้องการจริงๆ (รอบนี้รู้สึกจะลอง\u003cstrong\u003eJIRA\u003c/strong\u003eด้วยยิ่งใช้ยากหนักขึ้นไปอีก) สุดท้ายครับเราตัดสินใจกลับคืนสู่สามัญสู่จุดเริ่มต้นที่เราเคยได้ลองเพียงน้อยนิดและ\u003ca href=\"http://yothinix.blogspot.com/2013/08/change-1.html\"\u003eประสบความล้มเหลวกับ Project ก่อนหน้าไป\u003c/a\u003eและเราไม่ได้ใช้มันอีกเลยเรากลับมาลองมันอีกครั้งนั่นคือจุดเริ่มต้นที่เรากลับมาใช้\u003cstrong\u003ePhysical Board\u003c/strong\u003e ครับ\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/evolution-of-agile-board-at-adwise/IMG_20131205_235057_hu_d650ba12bc9e9b37.webp\"\n       srcset=\"/evolution-of-agile-board-at-adwise/IMG_20131205_235057_hu_82a9cc70c2987a8b.webp 480w, /evolution-of-agile-board-at-adwise/IMG_20131205_235057_hu_e840a1f6df8fd579.webp 960w, /evolution-of-agile-board-at-adwise/IMG_20131205_235057_hu_d650ba12bc9e9b37.webp 1440w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"1440\" height=\"1066\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e","title":"วิวัฒนาการของบอร์ดที่ ADWISE"},{"content":"จริงๆ ตอนแรกผมว่าจะไม่เขียน ตอนที่ 2 นี่แล้วเนื่องจากเหตุผลหลักเลยขี้เกียจและงานยุ่งมาก แต่พอวันหนึ่งผมเปิดเช็คยอดวิวของบล็อกอันนี้ ผมถึงเห็นว่ายังมีคนรออยู่ นอกจากนั้นแล้วการได้ยินเสียงตอบรับจากน้องที่เคยสอนการใช้ Git ไปว่ายังใช้ไม่ค่อยเป็น ทำให้ผมตระหนักว่าต้องกลับมาเขียนมันจริงๆ ถึงมันจะเป็นเรื่องเบสิกมากๆ ก็จริงๆ ในมุมมองเรา แต่สำหรับบางคนบางครั้งมันเป็นเรื่องใหม่สำหรับเขา เพราะฉะนั้นแล้วเนี่ยแทนที่เราจะนั่งเฉยๆ ปล่อยให้เขาล้มหายตายจากไป ผมคิดว่าอย่างน้อยเราก็ควรจะแบ่งปันความรู้ไว้บ้าง และเป็นการทวนความรู้ตัวเองจริงๆ อีกด้วยว่ารู้จริงรึเปล่า\nจากตอนที่แล้วผมบุ่มบ่ามมาพูดถึง Workflow ทั้งๆ ที่คนอ่านนั้นอาจจะไม่รู้เลยด้วยซ้ำว่าการแตก Branching หรือการรวม Merging และจากประสบการณ์ไปสอนกลุ่มย่อยๆ 2 กลุ่มทำให้รู้ว่า เรื่อง Branching/Merging เป็นเรื่องที่สอนให้คนเข้าใจจริงๆ ยากที่สุด และมีเวลาสอนน้อยสุดเพราะเป็นเรื่องหลังๆ เลยงั้นคราวนี้ ผมจะไล่ใหม่ทีละหัวข้อ รวมถึงเอาประสบการณ์มาสอดแทรกไว้ด้วยถ้ามีโอกาส (การใช้งานผมใช้ SourceTree เป็นหลักนะครับ ถ้ามีใครเป็นสิงห์ Git Command มาก็ขอนับถือในความสามารถมา ณ ที่นี้ครับ)\nClone/New สิ่งนี้เป็นสิ่งแรกที่ต้องทำเมื่อเราจะใช้งาน Git กับ Project ใดๆ ก็ตามไม่ว่าจะทำเองหรือทำกับทีม สิ่งสำคัญ 2 สิ่งสำหรับการ Clone ก็คือ Source Path กับ Destination Path โดย Source Path จะเป็น link ของ Remote repository ไว้สำหรับเก็บ Source code นอกเครื่องเรา (ที่เราเรียกว่า Local repository) โดยส่วนใหญ่มักจะอยู่ในรูป http url หรือ ssh url เช่น https://github.com/user/project.gitพอเราได้ลิงค์มาแล้วแปะไว้โปรแกรมจะสร้าง Destination Path ซึ่งเป็นโฟลเดอร์ที่เราจะใช้ในการเก็บไฟล์ที่เรา Clone มานี้และเป็นโฟลเดอร์หลักที่เราจะใช้ในการทำงานในโปรเจ็คนี้นะครับ โดยถ้าไม่พอใจก็เปลี่ยนได้ซึ่งส่วนใหญ่ก็จะเปลี่ยนอยู่แล้วเพราะคงไม่มีใครไปนั่งพัฒนาเว็บอยู่ใน My Document หรอกจริงมั้ยครับ\nส่วนในกรณีมี Project อยู่ในเครื่องหรือกำลังจะเริ่มสร้าง Project ในเครื่องเราก็จะมายุ่งในแท็บที่ 2 และ 3 แทนโดยในแท็บที่ 2 จะเป็นกรณีที่เรามีไฟล์ Project อยู่ในเครื่องอยู่แล้ว แล้วต้องการเอา Git ไปใช้งานเราก็เพียงแค่เพิ่ม Working copy path เข้าไปซึ่งก็คือ Destination Path ของกรณีที่แล้วนั่นเองครับ กรณีเราจะเริ่มสร้าง Project จากศูนย์เลยเราก็จะมายุ่งในแท็บที่ 3 ซึ่งก็คือการเพิ่ม Destination Path เข้าไปให้โปรแกรมมันจับแค่นั้นเองครับ\nFetch/Pull ในการทำงานประจำวันของผมกับ Git คำสั่ง 2 คำสั่งนี้จะเป็นสิ่งแรกที่ผมทำในทุกวันหลังจากเปิดโปรแกรมครับ โดยคำสั่งแรกก็คือ Fetch จุดประสงค์ของมันก็เพื่อเช็คว่ามีการกระทำอะไรใดๆ ใน remote repository ที่เราใช้อยู่รึเปล่า ซึ่งถ้ามีตัวโปรแกรมก็จะแจ้งเตือนเป็นตัวเลขจำนวน Commit พร้อมกับลูกศรลงอยู่ข้างหลัง Branch นั้นๆ หรือถ้าเราอยู่ใน Branch นั้นแล้วมันจะแสดงเป็นตัวเลขแดงๆ อยู่ตรงปุ่ม Pull กลายๆ ว่าเมิงกดกูซักทีเหอะนะซึ่งถ้าเรากดปุ่ม Pull ก็จะเป็นการดาวน์โหลดการเปลี่ยนแปลงใดๆ ที่เกิดใน Branch นั้นที่อยู่บน Remote repo ลงมายัง Branch เดียวกันที่อยู่เครื่องเราเป็นการทำให้แน่ใจว่าเครื่องเรามี Source code ล่าสุดพร้อมสำหรับการพัฒนาต่อเสมอ\nCommit คำสั่งนี้เป็นคำสั่งพื้นฐานที่สุดและใช้บ่อยที่สุดสำหรับ Git โดยการ Commit คือการเก็บบันทึกการเปลี่ยนแปลงใดๆ ที่เราทำใน Working Folder หรือโฟลเดอร์ Project ของเราเองไว้ ซึ่งก็จะแบ่งเป็น 2 Mode หลักๆ คือ Stage changes และ Working copy change โดย Stage change คือการเปลี่ยนแปลงที่เรากระทำกับไฟล์ในโฟลเดอร์นั้นๆ เช่น การสร้างไฟล์, การลบไฟล์ รวมถึงการ Merge Branch หลายๆ ครั้งเราก็จะใช้ Mode นี้ด้วย ส่วน Mode Working copy change คือการเปลี่ยนแปลงใดๆ ที่เรากระทำกับไฟล์ใดๆ ที่มีอยู่แล้วในโฟลเดอร์นั้น (ซึ่งอันนี้ใช้บ่อยที่สุดละ) ข้อควรระวังก็คือ ถ้าเราต้องการเปลี่ยนไป Branch อื่นๆ เช่นจาก Feature หนึ่งไปอีก Feature หนึ่งถ้ามีการเปลี่ยนแปลงใดๆ ที่ทำไปแล้วก็ควรจะ Commit ก่อนเปลี่ยน Branch (ซึ่งโดยปกติแล้วโปรแกรมจะเตือนไม่ให้เปลี่ยน แต่ก็จะมีตัวเลือก discard all change ไว้ในกรณีขี้เกียจด้วย)\nPush หลังจากเรากด commit ไปแล้วการเปลี่ยนแปลงนั้นก็เพียงแค่บันทึกไว้ใน Local repository ซึ่งถ้าเครื่องเรา HDD พัง OS เจ๊งก็ยังมีโอกาสที่เราจะสูญเสีย Source code ที่เราอุตส่าห์พร่ำเขียนมา ซึ่งการที่เรามี Remote repository ก็เพื่อป้องกันเหตุร้ายดังกล่าว (แต่ก็ใช้ว่ามันจะไม่มีโอกาสเสียเลย) รวมถึงเป็นการ Synchronous ตัวงานหรือโมดูลที่เราทำเข้ากับส่วนกลางเพื่อให้คนอื่นในทีมได้ใช้งานร่วมกันรวมถึงรวมเข้าด้วยกันในภายหลังโดยการ Push เราสามารถเลือกได้ว่าจะ Push ทุก Branch ที่มีอยู่ในเครื่องหรือเพียงแค่ Branch ที่เราได้ทำการเปลี่ยนแปลงไปในข้างต้น ข้อควรระวังคือโปรแกรมจะไม่ให้เรากด Push ถ้ามีการค้าง Pull ไว้ใน Branch ที่เราเลือก วิธีแก้ก็คือ Pull มันลงมาซะแล้วค่อยกด Push ใหม่อีกรอบหนึ่ง\nBranch/Merge/Checkout อย่างที่ผมได้กล่าวไปแล้วในตอนที่ 1 เรื่องแนวทางการแตก Branch จากประสบการณ์ผมเคยแตก Branch เองจริงๆ น้อยมากครับ ส่วนใหญ่จะใช้ฟีเจอร์ Git Flow ให้เป็นประโยชน์โดยหลังจากที่เราสร้าง Project มาแล้วการกด Git Flow ครั้งแรกจะเป็นการ Initial ตัว Local repository เราว่า เราจะทำงานแบบ Git Flow นะโดยตัวโปรแกรมก็จะแยก Branch ใหม่ให้เองเป็น Master กับ Develop ก่อนโดยเราจะถูกสลับ (Checkout) มาไว้ที่ Branch นี้โดยอัตโนมัติ หลังจากนั้นแล้วเมื่อเราต้องการพัฒนาฟีเจอร์ใหม่ใดๆ ก็กดตรง Git Flow แล้วเลือก Start New Feature ซึ่งส่วนใหญ่แตกแล้วแตกยาว เพราะหลายงานที่ทำอยู่ปัจจุบันก็ยังทำไม่เสร็จจน Finish Feature ซึ่งตัวโปรแกรมจะทำการรวม (Merge) ตัว Branch Feature นั้นๆ เข้า Develop ให้โดยอัตโนมัติ วิธีแก้ปัญหาในปัจจุบันส่วนใหญ่ผมยังใช้การ Merge เองด้วยมือในตอนวันท้ายๆ ของสัปดาห์ซึ่งเป็นการ Release ตัว Project ออกมาเป็นเวอร์ชั่นย่อยๆ รวมถึงเป็นการรวม Source Code จากคนอื่นๆ ในทีมมาอัพเดทไว้ที่ Branch Develop ด้วยซึ่งถ้าคนในทีมเริ่มแก้ไฟล์เดียวกันเมื่อไร สิ่งที่ตามมาอยู่ในย่อหน้าถัดไปครับ\nMerge Conflict เป็นปัญหาที่เกิดขึ้นจากการแก้ไขไฟล์เดียวกันในบรรทัดเดียวกันจากต่าง Branch กันซึ่งพอเราจะกด Merge ตัวโปรแกรมก็จะงงว่าตกลงเราจะเอาอันไหน ซึ่งมีตัวเลือกในการแก้ (resolve conflict) อยู่ 2 ทางคือใช้ไฟล์ของเรา หรือใช้ไฟล์จากอีก Branch หนึ่งที่กำลังจะรวมเข้าไป ซึ่งอันนี้ก็ขึ้นอยู่กับสถานการณ์ว่าจะใช้แบบไหนในการแก้\nสิ่งที่เกิดขึ้นหลังจากแตก Branch อย่างเมามันส์\u0026hellip; นรกของการ Merge Code\nTag ตอนผมเริ่มใช้ Git ใหม่ๆ ผมยอมรับเลยว่าผมไม่เคยเห็นความสำคัญของ Tag เลย จนกระทั่งผมกับทีมเริ่มแตก Branch มากกว่า 5 สายผมถึงเริ่มเข้าใจทันที่ว่าเรามี Tag ไว้เพื่ออะไร การติด Tag ก็เหมือนการติดป้ายบอกว่าเราทำอะไรอยู่ในตรงนั้นนอกจาก Commit message โดยส่วนใหญ่จะติดตอน Finish Feature หรือ Release เป็นการอ้างอิงถึงที่หาง่ายกว่า Commit Message มากโดยตัว Git Flow จะมีตัวเลือกให้เราใส่ Tag โดยอัตโนมัติเมื่อเข้าสู่เงื่อนไขดังกล่าวข้างต้น\nอย่างไรก็ตามการใช้งาน Git ยังมีคำสั่งอื่นๆ ที่ต้องใช้งานในโอกาสต่างๆ กันอีกหลายคำสั่งซึ่งผมก็คงอธิบายไม่หมด โดยคำสั่งข้างต้นเพียงเท่านี้ก็น่าจะสามารถช่วยให้ทำงานโดยใช้ Git ได้ในระดับนึงแล้ว อย่างไรก็ตามการใช้ Git ก็เหมือนกับ Practice อื่นๆ ซึ่งการอ่านเพียงอย่างเดียวคงไม่สามารถช่วยแก้ปัญหาที่เจอได้ ต้องลองใช้ ลองพัง ลองแก้ แล้วจะรู้ว่า Git มันช่วยชีวิตคนมาแล้วมากมายจริงๆ\nปล.ถ้าผมอธิบายงง ก็แสดงว่าผมสอนไม่รู้เรื่องจริงๆ ถ้าผู้อ่านท่านใดยังงงกับที่ผมอธิบายอยู่สามารถทิ้งความคิดเห็นไว้ได้ซึ่งทางผมจะได้นำไปปรับปรุงรวมถึงแก้ไขความเข้าใจต่อไปครับ\nOriginal post at: https://yothinix.blogspot.com/2013/12/tde-2-git-basix-command.html\n","permalink":"https://yothinix-com.pages.dev/tde-2-git-basix-command/","summary":"\u003cp\u003eจริงๆ ตอนแรกผมว่าจะไม่เขียน ตอนที่ 2 นี่แล้วเนื่องจากเหตุผลหลักเลยขี้เกียจและงานยุ่งมาก แต่พอวันหนึ่งผมเปิดเช็คยอดวิวของบล็อกอันนี้ ผมถึงเห็นว่ายังมีคนรออยู่ นอกจากนั้นแล้วการได้ยินเสียงตอบรับจากน้องที่เคยสอนการใช้ Git ไปว่ายังใช้ไม่ค่อยเป็น ทำให้ผมตระหนักว่าต้องกลับมาเขียนมันจริงๆ ถึงมันจะเป็นเรื่องเบสิกมากๆ ก็จริงๆ ในมุมมองเรา แต่สำหรับบางคนบางครั้งมันเป็นเรื่องใหม่สำหรับเขา เพราะฉะนั้นแล้วเนี่ยแทนที่เราจะนั่งเฉยๆ ปล่อยให้เขาล้มหายตายจากไป ผมคิดว่าอย่างน้อยเราก็ควรจะแบ่งปันความรู้ไว้บ้าง และเป็นการทวนความรู้ตัวเองจริงๆ อีกด้วยว่ารู้จริงรึเปล่า\u003c/p\u003e\n\u003cp\u003eจาก\u003ca href=\"/team-development-environment-workflow-1-version-control-system/\"\u003eตอนที่แล้ว\u003c/a\u003eผมบุ่มบ่ามมาพูดถึง Workflow ทั้งๆ ที่คนอ่านนั้นอาจจะไม่รู้เลยด้วยซ้ำว่าการแตก Branching หรือการรวม Merging และจากประสบการณ์ไปสอนกลุ่มย่อยๆ 2 กลุ่มทำให้รู้ว่า เรื่อง Branching/Merging เป็นเรื่องที่สอนให้คนเข้าใจจริงๆ ยากที่สุด และมีเวลาสอนน้อยสุดเพราะเป็นเรื่องหลังๆ เลยงั้นคราวนี้ ผมจะไล่ใหม่ทีละหัวข้อ รวมถึงเอาประสบการณ์มาสอดแทรกไว้ด้วยถ้ามีโอกาส (การใช้งานผมใช้ \u003ca href=\"http://www.sourcetreeapp.com/\"\u003eSourceTree\u003c/a\u003e เป็นหลักนะครับ ถ้ามีใครเป็นสิงห์ Git Command มาก็ขอนับถือในความสามารถมา ณ ที่นี้ครับ)\u003c/p\u003e\n\u003ch1 id=\"clonenew\"\u003eClone/New\u003c/h1\u003e\n\u003cp\u003eสิ่งนี้เป็นสิ่งแรกที่ต้องทำเมื่อเราจะใช้งาน Git กับ Project ใดๆ ก็ตามไม่ว่าจะทำเองหรือทำกับทีม สิ่งสำคัญ 2 สิ่งสำหรับการ Clone ก็คือ Source Path กับ Destination Path โดย Source Path จะเป็น link ของ Remote repository ไว้สำหรับเก็บ Source code นอกเครื่องเรา (ที่เราเรียกว่า Local repository) โดยส่วนใหญ่มักจะอยู่ในรูป http url หรือ ssh url เช่น \u003ca href=\"https://github.com/user/project.git\"\u003ehttps://github.com/user/project.git\u003c/a\u003eพอเราได้ลิงค์มาแล้วแปะไว้โปรแกรมจะสร้าง Destination Path ซึ่งเป็นโฟลเดอร์ที่เราจะใช้ในการเก็บไฟล์ที่เรา Clone มานี้และเป็นโฟลเดอร์หลักที่เราจะใช้ในการทำงานในโปรเจ็คนี้นะครับ โดยถ้าไม่พอใจก็เปลี่ยนได้ซึ่งส่วนใหญ่ก็จะเปลี่ยนอยู่แล้วเพราะคงไม่มีใครไปนั่งพัฒนาเว็บอยู่ใน My Document หรอกจริงมั้ยครับ\u003c/p\u003e","title":"TDE\u0026W (2) :: GIT BASIX COMMAND"},{"content":"สิ่งหนึ่งที่เป็นเรื่องที่เกิดขึ้นเสมอเมื่อคุณทำงานร่วมกับคนอื่นก็คือ \u0026ldquo;ดราม่า\u0026rdquo; ครับไม่ว่าทีมคุณจะห่วยแตกจะเข้ากันดีมากจะสมบูรณ์แบบแค่ไหนอย่างน้อยต้องมีสักครั้งที่เกิดเรื่อง \u0026ldquo;ดราม่า\u0026rdquo; ขึ้นในทีมซึ่งการเกิดดราม่าในทีมไม่ใช่สิ่งที่แย่เสมอไปจริงอยู่มันอาจจะทำให้ทีมเกิดปัญหาเสียจังหวะหรือโมเมนตัมที่กำลังดำเนินอยู่ไปเพราะความเห็นต่างหรือการไม่พอใจเพียงอย่างใดอย่างหนึ่งก็ตามแต่สุดท้ายแล้วถ้าคุณเป็นอไจล์ทีมสิ่งหนึ่งที่คุณควรจะทำเมื่อเกิดเหตุการณ์เหล่านี้ขึ้นคือ Retrospective ครับ\nRetrospective คืออะไร ตามทำเนียมการทำสกรัม (ซึ่งเป็นกลวิธีแบบอไจล์แบบหนึ่ง) การทำ Retrospective เป็นการกระบวนการรูปแบบหนึ่งที่ใช้ในการตรวจสอบและปรับปรุงการทำงานของทีมโดยมักจะทำเมื่อสิ้นสุดทุกๆสปรินต์ (2 สัปดาห์) การทำ Retrospective จะช่วยให้ทีมเห็นปัญหาที่เกิดขึ้นในการทำงานของทีมได้อย่างชัดเจนยิ่งขึ้นซึ่งจะช่วยให้ทีมนั้นสามารถปรับปรุงขั้นตอนการทำงานที่เป็นปัญหาอยู่และส่งผลให้สามารถทำงานได้อย่างมีประสิทธิภาพมากยิ่งขึ้น\nผมรู้จักการทำ Retrospective ครั้งแรกในวันเดียวกับที่ผมรู้จัก Agile เป็นครั้งแรกที่งาน Agile Thailand 2013 ในวันนั้นมี Session หนึ่งที่ผมไปเข้าในตอนบ่ายชื่อว่า Retrospective: The art of continuous improvement ซึ่งสิ่งที่ดีที่สุดใน Session นี้นอกจากได้รู้ว่า Retrospective คืออะไรแล้วยังได้ฟังประสบการณ์จริงๆด้วยว่าทำแล้วเกิดอะไรขึ้นต่อมาและนั้นคือเหตุผลให้ผมอยากทำมาตลอดแต่ไม่มีโอกาสและที่สำคัญไม่มีดราม่า\nDrama นั้นสำคัญไฉน การเกิดดราม่าอย่างที่ผมบอกไปมักเกิดจากความเห็นที่แตกต่างหรือความไม่พอใจในระดับปัจเจกบุคคลซึ่งเราไม่สามารถบอกได้ชัดเจนว่าดราม่าเกิดตรงไหนบางครั้งมันเป็นการสั่งสมมานานบางครั้งมันเป็นการปะทะกันภายในเวลาไม่กี่ชั่วโมงแต่เมื่อเกิดดราม่าขึ้นแล้วถ้าคุณเป็นฝ่ายก่อดราม่า (ซึ่งในกรณีผมผมเป็นคนก่อดราม่า) สิ่งแรกที่ควรทำคือเอาอารมณ์ออกจากความคิดให้หมดแน่นอนว่ามันเป็นสิ่งที่ทำได้ยาก (จริงๆแล้วโคตรยากเลย) แต่เมื่ออารมณ์และบรรยากาศมาคุได้ผ่านพ้นไปแล้วหลายครั้งที่คุณจะค้นพบว่าบางครั้งปัญหาที่ทำให้เกิดดราม่ามันไม่ใช่เรื่องใหญ่และซับซ้อนเลยและในเมื่อคุณเริ่มจะมีเหตุผลขึ้นแล้วสิ่งที่ควรทำต่อมาคือเรียนรู้จากมันและการที่เราเป็นอไจล์ทีมแล้วการปรับปรุงการทำงานของทีมก็เป็นส่วนหนึ่งที่เราควรจะทำอย่างสม่ำเสมอ\nGood Bad Try จริงๆแล้ววิธีการทำ Retrospective นั้นมีหลายแบบมากๆแต่ที่ผมรู้จักและเลือกที่จะเอามาใช้คือ Good Bad Try ครับจริงๆแล้วผมบอกตามตรงเลยว่าผมไม่รู้ว่า Good Bad Try แบบจริงๆตามหลักการนั้นทำยังไงนอกจากมีคำว่า Good Bad Try และให้ทุกคนในทีมเอากระดาษโพสอิทไปแปะแต่สิ่งที่ผมจะกล่าวต่อไปคือขั้นตอนการทำ Good Bad Try ในแบบฉบับของทีมผมเอง\nขั้นแรกผมแจกกระดาษโพสอิทให้แต่ละคนในทีมโดยแต่ละคนก็จะได้สีแตกต่างกันไป (โชคดีที่ทีมผมมีแค่ 3 คนสีมันก็เลยไม่เยอะจนเกินไป) แล้วให้แต่ละคนในทีมเขียนใน 3 อย่างคือ\nสิ่งที่คิดว่าตัวเองทำได้ดี สิ่งที่คิดว่าตัวเองทำได้ไม่ดี สิ่งที่คิดว่าตัวเองควรจะปรับปรุง ซึ่งแน่นอนว่าการให้มนุษย์ยอมรับข้อผิดพลาดของตัวเองหรือแม้กระทั่งบอกข้อดีของตัวเองนั้นเป็นเรื่องที่ยากมากพอๆกันผมกำหนดเวลาให้ 7 นาทีในการเขียนสิ่งดังกล่าวแล้วเอามันไปแปะมันไว้บนบอร์ดช่วงห้านาทีแรกเป็นช่วงที่ผมรู้สึกได้ทันทีเลยว่าเป็นช่วงเวลาเปิดใจทีมการจะเขียนอะไรสักอย่างลงไปในกระดาษกลายเป็นเรื่องที่ยากพอๆกับการเขียน Method เพื่อแก้ปัญหาซักอย่างหนึ่งแต่พอผ่านพ้น 5 นาทีแรกไปแล้วทุกคนในทีมก็เริ่มรู้สึกว่ามีอะไร \u0026ldquo;อยากจะเขียน\u0026rdquo; มากขึ้นเรื่อยๆหลายๆเรื่องเป็นเรื่องที่ชวนขบขันและไม่จริงจังแต่หลายๆเรื่องกลายเป็นเรื่องที่เราทุกคนในทีมไม่เคยคิดเลยว่าเราจะคิดเหมือนๆกันพอหมด 7 นาทีในขณะที่ทุกคนในทีมกำลังสนุกกับการเริ่มเขียนสิ่งที่ \u0026ldquo;ตัวเองคิด\u0026rdquo; ลงไปในกระดาษผมต่อเวลาให้ทีมอีก 3 นาทีจนหมดเวลาก็มีกระดาษโพสอิทติดอยู่ใต้หัวข้อเต็มไปหมด (โดยเฉพาะ Try)\nต่อมาผมเก็บกระดาษโพสอิทแต่ละสีจากทุกคนในทีมคืนแล้วแบ่งกระดาษโพสอิทสีเหลืองสีเดียวออกเป็น 3 ส่วน (ซึ่งมาจากสมาชิก 3 คนในทีม) เท่าๆกันจากนั้นผมบอกให้ทุกคนในทีมเขียนเหมือนกับขั้นตอนที่ 1 อีกครั้งแต่คราวนี้เปลี่ยนจากการเขียนเกี่ยวกับตัวเองเป็นการเขียนถึงเพื่อนร่วมทีมผมให้เวลากับทีม 5 นาทีแต่ครั้งนี้ไม่มีปัญหาในการคิดอะไรจะเขียนเหมือนรอบแรกอีกแล้วอาจเป็นเพราะไม่ใช่เรื่องเกี่ยวกับตัวเองแต่ละคนถึงสบายใจขึ้นที่จะเขียนหรือไม่ก็อาจจะเป็นเพราะบางครั้งเรามองเห็นข้อดี, ข้อผิดพลาดของคนอื่นได้ดีกว่าของตัวเราเองก็เป็นได้พอหมด 5 นาทีเราก็มีข้อมูลสำหรับปรับปรุงทีมเป็นตับๆเลยทีเดียว\nก่อนที่ทีมจะไปดูบอร์ดผมเริ่มตั้งคำถามกับทุกคนในทีมว่า \u0026ldquo;มีอะไรอยากจะพูดมั้ยเรื่องอะไรก็ได้\u0026quot;ซึ่งก็เป็นไปตามคาดว่ามักจะไม่มีใครกล้าพูดถึงแม้จะทำงานมาด้วยกันมาหลายสัปดาห์แล้วก็ตามวิธีการแก้ปัญหาในข้อนี้ผมเลือกที่จะเป็นคนพูดก่อนซึ่งผมเรียนรู้มาตลอดว่าเหตุผลที่คนส่วนใหญ่ไม่พูดไม่ใช่เพราะไม่มีเรื่องที่จะพูดแต่เพราะไม่อยากเป็นคนแรกที่พูดออกไปอย่างไรก็ตามเมื่อผมพูดจบทีมยังคงเงียบอยู่ซึ่งนั้นทำให้ผมต้องรุกเร้าและกระตุ้นให้ทีมซึ่งในท้ายที่สุดก็เริ่มพูดกันออกมาจนได้และนี่ทำให้เรารู้ความคิดเห็นในหลายๆเรื่องของเพื่อนในทีมมากกว่าการนั่งแยกย้ายกันทำงานไปในแต่ละวันเสียอีก\nเมื่อถึงเวลาดูบอร์ดหลายๆอย่างเป็นไปตามคาดไว้นั้นแสดงให้เห็นว่าไม่ว่าจะเป็นข้อดี, ปัญหาหรือสิ่งที่เราพยายามจะแก้ไขหลายๆอย่างนั้นดูเหมือนเราจะเข้าใจมันดีอยู่แล้วแต่หลายๆอย่างทีมของเราไม่เคยคิดมาก่อนเลยว่ามันจะเป็นปัญหาหรืออย่างน้อยในมุมมองของคนอื่นๆในทีมข้อสำคัญคือข้อความในกระดาษโพสอิทแต่ละอันก็เหมือน Task ที่เราเขียนไว้ใน Backlog หลายๆครั้งเราที่เราไม่เข้าใจว่าคนอื่นเขียนอะไรลงไปสิ่งที่จะตามมาก็คือเราต้องให้เจ้าของกระดาษโพสอิทนั้นอธิบายซึ่งถ้ายังไม่เข้าใจอยู่ต้องจบด้วยคำว่า \u0026ldquo;ยกตัวอย่างเช่น\u0026rdquo; (เอาเทคนิคนี้มาจาก TPSE Conference) เมื่อเรายกประเด็นในเรื่องใดขึ้นมาพูดแล้วสิ่งที่ตามมามักจะเป็นวิธีแก้ปัญหาและสิ่งที่คนนั้นควรจะปรับปรุงซึ่งหลายๆครั้งคนที่ถูกพูดถึงในการ์ดเองก็มองข้ามวิธีเหล่านี้ไปสิ่งนี้ผมถือว่าเป็นสิ่งที่เราได้อะไรมากที่สุดจากการทำ Retrospective ในครั้งนี้เลย\nการจบ Retrospective เทคนิคนี้ผมยอมรับเลยว่าเอามาจากการไปฟัง Session นี้ที่งาน Agile Thailand 2013 โดยในขณะที่เรายังรู้สึกอินกับการเปิดใจและยอมรับความคิดเห็นของทีมในแต่ละประเด็นอยู่นั้นเมื่อถึงจุดที่ใกล้จะสิ้นสุดทุกคนในทีมจะรู้สึกคล้ายๆกันคือยอมรับข้อผิดพลาดและมุ่งมั่นที่จะเริ่มการปรับปรุงตัวเองเพื่อทีมแต่ก่อนที่จะจบนั้นผมเริ่มด้วยการกล่าวขอบคุณทุกคนในทีมและเพื่อนบางคนที่อยู่ที่ห้องโปรเจ็คในเวลานั้นมันเป็นช่วงเวลาที่ผมรู้สึกดีมากๆผมกล่าวขอบคุณทุกคนจากใจจริงขอบคุณทุกคนที่เปิดใจและทำให้เรารู้สึกร่วมกันความรู้สึกที่ทำให้เราเป็นทีมเดียวกัน (หลังจากผ่านวันที่โหดร้ายมาในตอนบ่ายวันเดียวกันนั้นเอง) ซึ่งหลังจากนั้นทีมเราก็ประชุมกันต่อในหัวข้อต่อไปแต่สิ่งหนึ่งที่ผมรู้สึกได้ในเวลานั้นก็คือ Mindset ของทีมได้เปลี่ยนไปแล้วและมันกำลังจะไปในทางที่ดีขึ้นหรืออย่างน้อยผมก็เชื่อว่ามันจะเป็นอย่างนั้น\nสิ่งที่ผมเรียนรู้จากการทำ Retrospective ครั้งนี้ ทุกๆ คนในทีมรู้ตัวว่าเขียนโค้ดไม่สะอาด, เละเทะและไม่เป็นระเบียบมาก แต่ทั้งๆ ที่รู้ตัวก็ยังเขียนแบบเดิมอยู่อย่างนั้น เรามีทั้งแม่พระ, ตัวก่อดราม่า ในทีมเดียวกัน เรามักจะคิดว่าตัวเองขี้เกียจ ในขณะที่คนอื่นมองว่าเราขยัน ปัญหาใน Try ส่วนใหญ่ไม่ใช่ปัญหาในตัวงานแต่เป็นปัญหาที่เกี่ยวกับสภาพแวดล้อมการทำงาน ผมเป็นคนจริงจังเกินไปในสายตาของเพื่อนร่วมทีม ซึ่งก็เป็นทั้งข้อดีและข้อเสียในเวลาเดียวกัน Original post at: https://yothinix.blogspot.com/2013/12/retrospective-drama.html\n","permalink":"https://yothinix-com.pages.dev/retrospective/","summary":"\u003cp\u003eสิ่งหนึ่งที่เป็นเรื่องที่เกิดขึ้นเสมอเมื่อคุณทำงานร่วมกับคนอื่นก็คือ \u0026ldquo;ดราม่า\u0026rdquo; ครับไม่ว่าทีมคุณจะห่วยแตกจะเข้ากันดีมากจะสมบูรณ์แบบแค่ไหนอย่างน้อยต้องมีสักครั้งที่เกิดเรื่อง \u0026ldquo;ดราม่า\u0026rdquo; ขึ้นในทีมซึ่งการเกิดดราม่าในทีมไม่ใช่สิ่งที่แย่เสมอไปจริงอยู่มันอาจจะทำให้ทีมเกิดปัญหาเสียจังหวะหรือโมเมนตัมที่กำลังดำเนินอยู่ไปเพราะความเห็นต่างหรือการไม่พอใจเพียงอย่างใดอย่างหนึ่งก็ตามแต่สุดท้ายแล้วถ้าคุณเป็นอไจล์ทีมสิ่งหนึ่งที่คุณควรจะทำเมื่อเกิดเหตุการณ์เหล่านี้ขึ้นคือ Retrospective ครับ\u003c/p\u003e\n\u003ch1 id=\"retrospective-คออะไร\"\u003eRetrospective คืออะไร\u003c/h1\u003e\n\u003cp\u003eตามทำเนียมการทำสกรัม (ซึ่งเป็นกลวิธีแบบอไจล์แบบหนึ่ง) การทำ Retrospective เป็นการกระบวนการรูปแบบหนึ่งที่ใช้ในการตรวจสอบและปรับปรุงการทำงานของทีมโดยมักจะทำเมื่อสิ้นสุดทุกๆสปรินต์ (2 สัปดาห์) การทำ Retrospective จะช่วยให้ทีมเห็นปัญหาที่เกิดขึ้นในการทำงานของทีมได้อย่างชัดเจนยิ่งขึ้นซึ่งจะช่วยให้ทีมนั้นสามารถปรับปรุงขั้นตอนการทำงานที่เป็นปัญหาอยู่และส่งผลให้สามารถทำงานได้อย่างมีประสิทธิภาพมากยิ่งขึ้น\u003c/p\u003e\n\u003cp\u003eผมรู้จักการทำ Retrospective ครั้งแรกในวันเดียวกับที่ผมรู้จัก Agile เป็นครั้งแรกที่งาน Agile Thailand 2013 ในวันนั้นมี Session หนึ่งที่ผมไปเข้าในตอนบ่ายชื่อว่า Retrospective: The art of continuous improvement ซึ่งสิ่งที่ดีที่สุดใน Session นี้นอกจากได้รู้ว่า Retrospective คืออะไรแล้วยังได้ฟังประสบการณ์จริงๆด้วยว่าทำแล้วเกิดอะไรขึ้นต่อมาและนั้นคือเหตุผลให้ผมอยากทำมาตลอดแต่ไม่มีโอกาสและที่สำคัญไม่มีดราม่า\u003c/p\u003e\n\u003ch1 id=\"drama-นนสำคญไฉน\"\u003eDrama นั้นสำคัญไฉน\u003c/h1\u003e\n\u003cp\u003eการเกิดดราม่าอย่างที่ผมบอกไปมักเกิดจากความเห็นที่แตกต่างหรือความไม่พอใจในระดับปัจเจกบุคคลซึ่งเราไม่สามารถบอกได้ชัดเจนว่าดราม่าเกิดตรงไหนบางครั้งมันเป็นการสั่งสมมานานบางครั้งมันเป็นการปะทะกันภายในเวลาไม่กี่ชั่วโมงแต่เมื่อเกิดดราม่าขึ้นแล้วถ้าคุณเป็นฝ่ายก่อดราม่า (ซึ่งในกรณีผมผมเป็นคนก่อดราม่า) สิ่งแรกที่ควรทำคือเอาอารมณ์ออกจากความคิดให้หมดแน่นอนว่ามันเป็นสิ่งที่ทำได้ยาก (จริงๆแล้วโคตรยากเลย) แต่เมื่ออารมณ์และบรรยากาศมาคุได้ผ่านพ้นไปแล้วหลายครั้งที่คุณจะค้นพบว่าบางครั้งปัญหาที่ทำให้เกิดดราม่ามันไม่ใช่เรื่องใหญ่และซับซ้อนเลยและในเมื่อคุณเริ่มจะมีเหตุผลขึ้นแล้วสิ่งที่ควรทำต่อมาคือเรียนรู้จากมันและการที่เราเป็นอไจล์ทีมแล้วการปรับปรุงการทำงานของทีมก็เป็นส่วนหนึ่งที่เราควรจะทำอย่างสม่ำเสมอ\u003c/p\u003e\n\u003ch1 id=\"good-bad-try\"\u003eGood Bad Try\u003c/h1\u003e\n\u003cp\u003eจริงๆแล้ววิธีการทำ Retrospective นั้นมีหลายแบบมากๆแต่ที่ผมรู้จักและเลือกที่จะเอามาใช้คือ Good Bad Try ครับจริงๆแล้วผมบอกตามตรงเลยว่าผมไม่รู้ว่า Good Bad Try แบบจริงๆตามหลักการนั้นทำยังไงนอกจากมีคำว่า Good Bad Try และให้ทุกคนในทีมเอากระดาษโพสอิทไปแปะแต่สิ่งที่ผมจะกล่าวต่อไปคือขั้นตอนการทำ Good Bad Try ในแบบฉบับของทีมผมเอง\u003c/p\u003e","title":"RETROSPECTIVE: เมื่อทีมเกิด DRAMA ทำไง ?"},{"content":"เมื่อวันพฤหัสและศุกร์ที่ผ่านมาผมได้มีโอกาสโดดเรียนวิชา DSP ไปร่วมงานThailand Practical Software Engineering Conferenceที่Software Parkมาครับซึ่งงานนี้เรียกได้ว่าเป็นครั้งแรกที่จัด (ในชื่อนี้) โดยกลุ่มผู้จัดงานก็คือThailand SPINซึ่งถ้าเคยไปร่วมงานสัมมนา Agile หลายๆงานมาก็จะค้นพบว่าคือวงการเดียวกันนี่แหละเป้าหมายของงานสัมมนานี้ตามที่ผมเข้าใจจากผู้จัดงานคือมาแลกเปลี่ยนประสบการณ์เกี่ยวกับ Software Process (ซึ่ง Agile ก็เป็นหนึ่งในนั้น) ของจริงเจ็บจริงไม่ใช่งานสัมมนาเพื่อมาขายของซึ่งนอกจากผู้จัดแล้วผมก็เพิ่งค้นพบอีกว่าวงการ Software บ้านเรานั้นมันไม่ได้กว้างใหญ่เลยปีนี้ไปมาแล้ว 3 งานคือ Agile Thailand 2013, Barcamp Bangkhen และงานนี้ก็เจอแต่คนหน้าเดิมๆอาจจะเจอคนหน้าใหม่ๆบ้างแต่ถือว่าน้อยมาก (แต่ก็ยังไม่กล้าทักใครก่อนอยู่ดี T^T) ข้อเสียอย่างเดียวของงานนี้ที่นึกออกคือการไปจัดอยู่ Software Park ซึ่งมันไกลมากจากลาดกระบังแต่นับว่าเดินทางสะดวกอยู่ทีเดียวคือนั่งรถเพียงแค่ 2 ต่อ (แต่ต้องขึ้น 166 ให้ถูกคันทั้งขาไปและกลับเลย) เกริ่นมานานแล้วมาไล่ดู Session ที่ผมไปเข้ามาดีกว่า\nKeynote: Challenges of Managing a Complex Project - The Case Study of Landing a Rover on Mars Session นี้ถือว่าเป็น Highlight ของงานเลยครับแค่คนพูดนี่ก็สุดๆแล้วDr.Firouz Naderiผู้อำนวยการโครงการสำรวจในระบบสุริยะทั้งหมดจาก NASA JPL เรียกได้ว่าตั้งแต่ดวงอาทิตย์ยันดาวพลูโต Dr. คนนี้มีเอี่ยวหมดโดยดร.ฟิรุสมาเล่าให้ฟังเกี่ยวกับโครงการสำรวจดาวอังคารที่แกกำลังทำอยู่โดยเริ่มการค่อยๆเกริ่นจากไอเดียภาพรวมของการทำโครงการซักโครงการนึงว่า 1)เราเริ่มจากการมีความฝันแล้ว 2)เราขายฝันจากนั้นแล้วในวันถัดมา 3)เราก็เริ่มจะคิดได้ว่า \u0026ldquo;กูมองโลกในแง่ดีเกินไปแล้วนะ\u0026rdquo; ซึ่งพอผ่านจุดนี้เราจะ 4)เริ่มทำงานหนักขึ้นที่ 60 ชั่วโมงต่อสัปดาห์และ 5)เราก็จะเริ่มเครียดขึ้นอีกเรื่อยๆจากปัญหาต่างๆที่รุมเข้ามาไม่ว่าจะเป็นปัญหาทางเทคนิค, งบหรือแม้กระทั่งกำหนดส่งปัญหาเหล่านี้จะส่งผลให้ 6)เราทำงานหนักขึ้นอีกเป็น 70 ชั่วโมงต่อสัปดาห์ซึ่งเมื่อถึงท้ายที่สุดแล้วไม่มีใครบอกได้ว่า 7)โครงการที่เราทำอยู่จะประสบความสำเร็จ\u0026hellip;.. หรือล้มเหลว\nดร.ฟิรุซบอกว่าในตอนเริ่มต้นของทุกโครงการทุกอย่างมักจะง่ายเสมอเขาใช้คำว่า \u0026ldquo;Give me the money I give you a profit\u0026rdquo; แต่ปัญหาก็คือบางคนที่เริ่มทำโครงการจากสิ่งที่คนอื่นทำมาก่อนแล้วนั้นมักจะไม่เข้าใจปัญหาพื้นฐานที่แท้จริงซึ่งเมื่อทำโครงการไปถึงจุดๆหนึ่งคนเหล่านั้นจะเจอทางตันจนไปต่อไม่ได้เหมือนกับนักวิ่งมาราธอนที่จะมีขีดจำกัดของตัวเองอยู่ (km ที่ 35) โดยดร. แนะนำว่าสิ่งแรกที่ควรจะทำในการทำโครงการที่ซับซ้อนมากๆไม่ใช่การหา Project Manager แต่เป็นเรื่องของทีมโดยดร.ฟิรุซสรุปสิ่งหน้าที่ๆสำคัญที่สุดของ Team Leader ให้เราไว้ 3 ข้อดังนี้\nต้องหาคนที่ \u0026ldquo;ดีที่สุด\u0026rdquo; ให้มาร่วมทีมกับเราให้ได้ซึ่งจะทำให้โอกาสที่ไอเดียที่เรามีประสบความสำเร็จได้สูงกว่าการหาคนที่ \u0026ldquo;ดีรองลงมา\u0026rdquo; แต่อย่างไรก็ตามการหาคนที่ดีที่สุดมาก็จำเป็นต้องทำให้แน่ใจให้ได้ว่าเขาเหล่านั้นเข้ากับคนอื่นในทีมได้เพราะคนที่ \u0026ldquo;เก่งที่สุด\u0026rdquo; ส่วนใหญ่มักจะมี EGO เสมอ ต้องกระตุ้น (Motivate) ทีมให้มีความมุ่งมั่นอยู่ตลอดเวลาโดยดร. ได้ยก Quote ของ Antoine de Saint-Exupéry ซึ่งผมก็สารภาพตามตรงว่าอ่านมาหลายรอบแล้วก็ยังไม่เข้าใจความหมายของมันมาว่า\u0026ldquo;If you want to build a ship, don’t drum up the men to gather wood, divide the work, and give orders. Instead, teach them to yearn for the vast and endless sea.\u0026quot; PM ควรจะต้องแชร์วิสัยทัศน์ร่วมกับทีมให้ตรงกันเหมือนนายพลกับกองทหารแต่ PM ที่ดีต้องยังเป็น Fair Leader ด้วยคือเป็นทั้งคนแรกที่รับคำด่าและคนแรกที่รับคำชม หลังจากนั้นแล้วดร.ฟิรุซก็เริ่มยกตัวอย่างของMars Exploration Programโดยดร. บอกว่าเป้าหมายของการสำรวจดาวอังคารนั้นก็เพื่อตอบคำถาม 3 ข้อคือ 1) ดาวอังคารเคยอาศัยอยู่ได้หรือไม่ ? 2) ถ้าได้เคยมีสิ่งมีชีวิตอยู่รึเปล่า ? 3) ถ้ามีตอนนี้มันยังอยู่มั้ยดร.ฟิรุซเล่าต่อไปว่ายานสำรวจCuriosityเป็นวัตถุลำดับที่ 50 ที่ไปดาวอังคารหนึ่งใน 23 โครงการที่ลงจอดสำเร็จถ้านั่นยังไม่เห็นภาพพอดร.ฟิรุซเปรียบเทียบว่าการส่งวัตถุไปดาวอังคารก็เหมือนการเตะลูกฟุตบอลจากโตเกียวมาลงที่สนามราชมังฯกรุงเทพฯซึ่งถ้าคิดว่านั้นยากแล้วให้คิดภาพไปอีกว่าสนามหมุนด้วยความเร็ว 100,000 กม./ชม. แต่นั้นไม่ใช่สิ่งที่ยากที่สุดสิ่งที่ยากที่สุดไม่ใช่การเดินทาง 9 เดือนไม่ใช่การหาจุดที่ต้องลงจอดแต่เป็น 7 นาทีสุดท้ายก่อนที่ยานจะลงจอด\nใน 7 นาทีสุดท้ายของการลงจอดนั้นยานจะพุ่งไปด้วยความเร็วถึง 20,000 mph ซึ่งยานสำรวจในยุคต่างๆกันจะใช้เทคนิคต่างกันโดยรุ่นแรกๆจะใช้ Airbags คือส่งตกลงไปก็เป็นลูกบอลลมกลิ้งไปกลิ้งมาจนหยุดแต่สำหรับ Curiosity นั้นไม่สามารถทำได้เนื่องจากมันใหญ่และหนักมากพอๆกับรถเก๋งคันหนึ่งเลยทีเดียวเลยต้องใช้เทคนิคพิเศษซึ่งสามารถไปค้นได้ตามWikipediaนะครับ\nพอลงจอดได้แล้วทำไรต่อคำถามที่นักวิทยาศาสตร์ต้องการคำตอบก็คือมันเกิดอะไรขึ้นที่นี่เมื่อ 1000 ปีที่แล้วซึ่งดร.ฟิรุซก็อธิบายให้ฟังว่าประวัติศาสตร์ของดาวนั้นจริงๆแล้วเขียนอยู่ในหินในแต่ละ Layer เหมือนหนังสือประวัติศาสตร์โดยคนที่อ่านหินพวกนั้นออกก็เดาได้ไม่ยากเลยนักธรณีวิทยาซึ่งนั่นก็ทำให้เกิดคำถามกับพวกเราว่าทำไมไม่ส่งคนจริงๆไปหล่ะดร.ฟิรุซได้ให้สาเหตุไว้ 4 ข้อคือ\nTechnical Problem เพราะเรายังไม่รู้ว่าจะขนของน้ำหนัก 40 ตันไปดาวอังคารยังไง Psychological Problem เพราะเราไม่รู้ว่าคนเราจะทนอยู่ใน Small Capsule ได้ถึง 9 เดือนหรือไม่ Biological Problem เพราะเราไม่รู้ว่าการอยู่ในอวกาศ นานขนาดนั้นจะส่งผลต่อร่างกายยังไงบ้าง Financial Problem อันนี้คงไม่ต้องอธิบาย ประมาณการไว้ว่าต้องใช้งบถึง Half Trillion Dollar เพราะฉะนั้นแล้วเนี่ยทาง NASA ถึงได้ส่งหุ่นไปทำหน้าที่แทนมนุษย์ หลังจากเกริ่นเรื่องการสำรวจดาวอังคารมาพอหอมปากหอมคอดร.ฟิรุซก็ได้พาเราย้อนกลับมาสู่เรื่องของโครงการกันต่อโดยเล่าให้เราฟังว่าปัญหาแรกอยู่ที่เรามีงบประมาณจำกัด (จากการเปลี่ยนผอ. ใหม่) เริ่มต้นเพียงแค่ 100M Dollar แต่ทีมก็ทำสำเร็จทำให้ได้เพิ่มงบจาก 240M เป็น 250M ซึ่งทำให้ดร.ฟิรุซสามารถทำโครงการสำรวจได้มากถึง 2 โครงการแต่ทุกโครงการย่อมมีความเสี่ยง 2 โครงการดังกล่าวล้มเหลวอย่างสิ้นเชิงซึ่งดร. ก็ได้ให้ข้อคิดที่ดีกับเราว่า \u0026ldquo;อย่ากลัวที่จะล้มเหลวและอย่าสิ้นหวังกับความล้มเหลวถ้าเราได้เรียนรู้จากความผิดพลาดที่ก่อให้เกิดความล้มเหลวความล้มเหลวนั้นก็ไม่ใช่ความล้มเหลวซะทั้งหมด\u0026rdquo; นอกจากนี้ดร.ฟิรุซยังแนะอีกว่าให้เราในฐานะ PM ยอมที่จะเสี่ยงกับโครงการที่ High Risk, High Reward โดยตัวดร.ฟิรุซเองนั้นมักมองหาโครงการที่ยากที่สุดเสมอโดยทำตามสูตร 3 ข้อของโครงการข้างบนแล้วโอกาสสำเร็จจะมากขึ้นเอง\nในการทำงานที่ NASA นั้นทุกครั้งที่มีการนำเสนอโครงการให้จะมี PM ของโครงการเก่าๆนั่งพิจารณาด้วยอยู่เสมอและบ่อยครั้งที่เรามักจะคิดผิดไปแต่บางครั้งเราก็ไม่ได้คิดผิดไปมากขนาดนั้นดร.ฟิรุซเล่าถึงโครงการ Mars Exploration Rover ว่าขณะ 1 ปีก่อนส่งจรวดทีมเขาก็ยังหาวิธีที่จะสร้าง Air Bag ไม่ได้เลยนอกจากนั้นแล้วยังเจอข้อจำกัดจากการที่จะสามารถส่งวัตถุไปดาวอังคารได้ภายในทุกๆ 26 เดือนเท่านั้นและโอกาสที่จะปล่อยจากโลกมีเพียงแค่ 21 วันซึ่งดร.ฟิรุซทำโครงการเสร็จแต่ใช้งบเกินไป 18% จากตอนขอครั้งแรกนอกจากนั้นแล้วดร.ฟิรุซยังยกตัวอย่างไว้อีกว่าช่วงวิกฤตของโครงการเช่นตอนกางร่มนั้นต้องการระยะที่เฉพาะมากๆแต่ก็มีปัญหาเข้ามาอีกคือช่วงนั้นเกิดพายุทรายในดาวอังคารซึ่งดร.ฟิรุซได้ฝากข้อคิดไว้ว่า \u0026ldquo;ในโครงการที่มีความซับซ้อนมากๆเราไม่เคยมีข้อมูลที่ครบถ้วนสำหรับการตัดสินใจและบ่อยครั้งที่เราต้องตัดสินใจจากข้อมูลที่ไม่สมบูรณ์แบบ\u0026rdquo;\nในช่วงของคำถามก็ยังมีคำถามที่น่าสนใจหลายๆคำถามด้วยกันโดยเฉพาะคำถามแรกที่มีผู้ถามดร.ฟิรุซว่าเราจะรวมทีมที่เป็น \u0026ldquo;The Avenger\u0026rdquo; เข้าด้วยกันได้ไง (คืนก่อนไปงานผมเพิ่งดู) ดร.ฟิรุซตอบโดยยกตัวอย่างเวลาเราอยู่ในสงครามนั้นถ้าคนเราโดนถล่มอยู่ในป้อมเดียวกันสุดท้ายแล้วทุกคนก็จะเริ่มสู้ด้วยกันเป็นทีมในสถานการณ์เดียวกันแต่อย่างไรก็ตามสำหรับทีมที่เป็น Super Star ต้องทำให้เขารู้สึกสบายใจที่จะทำงานด้วยได้และถ้ามีปัญหาก็ควรจะบอก PM ทันทีโดยที่ NASA การที่เราบอกถึงปัญหาและแก้ปัญหาได้จะทำให้เรานั้นรู้สึกเป็นเกียรติมากแต่สิ่งสำคัญและเป็นบทสรุปของคำตอบคือเราต้องWork on human personalityนอกจากนั้นแล้วก็ยังมีคำถามอื่นๆที่น่าสนใจเช่นทำไมเราไม่ส่งคนไปดาวอังคาร, ทำไมเราต้องสำรวจดาวอังคาร (ข้อนี้ทำให้ได้ความรู้ว่าจุดต่อไปที่ NASA สนใจคือดวงจันทร์ Europa ของดาวพฤหัส), เราจะจัดการความเปลี่ยนแปลงที่เกิดขึ้นอย่างไร (ได้ศัพท์ใหม่Requirement Creep ) และข้อสุดท้ายการสำรวจดาวอังคารเราจะออกแบบการจำลองสถานการณ์อย่างไรดร.ฟิรุซปิดท้ายด้วยคำตอบ \u0026ldquo;Test as you fly, Fly as you test\u0026rdquo;\nปล.แค่ Keynote วันแรกก็ซัดไป 1 Entry เต็มๆ แล้วจะพยายามมาส่งที่เหลือให้เร็วที่สุดครับ\nOriginal post at: https://yothinix.blogspot.com/2013/11/tpse-conference-2013-1-keynote.html\n","permalink":"https://yothinix-com.pages.dev/tpse-conference-2013-1-keynote/","summary":"\u003cp\u003eเมื่อวันพฤหัสและศุกร์ที่ผ่านมาผมได้มีโอกาสโดดเรียนวิชา DSP ไปร่วมงาน\u003cstrong\u003eThailand Practical Software Engineering Conference\u003c/strong\u003eที่\u003cstrong\u003eSoftware Park\u003c/strong\u003eมาครับซึ่งงานนี้เรียกได้ว่าเป็นครั้งแรกที่จัด (ในชื่อนี้) โดยกลุ่มผู้จัดงานก็คือ\u003cstrong\u003eThailand SPIN\u003c/strong\u003eซึ่งถ้าเคยไปร่วมงานสัมมนา Agile หลายๆงานมาก็จะค้นพบว่าคือวงการเดียวกันนี่แหละเป้าหมายของงานสัมมนานี้ตามที่ผมเข้าใจจากผู้จัดงานคือมาแลกเปลี่ยนประสบการณ์เกี่ยวกับ Software Process (ซึ่ง Agile ก็เป็นหนึ่งในนั้น) ของจริงเจ็บจริงไม่ใช่งานสัมมนาเพื่อมาขายของซึ่งนอกจากผู้จัดแล้วผมก็เพิ่งค้นพบอีกว่าวงการ Software บ้านเรานั้นมันไม่ได้กว้างใหญ่เลยปีนี้ไปมาแล้ว 3 งานคือ Agile Thailand 2013, Barcamp Bangkhen และงานนี้ก็เจอแต่คนหน้าเดิมๆอาจจะเจอคนหน้าใหม่ๆบ้างแต่ถือว่าน้อยมาก (แต่ก็ยังไม่กล้าทักใครก่อนอยู่ดี T^T) ข้อเสียอย่างเดียวของงานนี้ที่นึกออกคือการไปจัดอยู่ Software Park ซึ่งมันไกลมากจากลาดกระบังแต่นับว่าเดินทางสะดวกอยู่ทีเดียวคือนั่งรถเพียงแค่ 2 ต่อ (แต่ต้องขึ้น 166 ให้ถูกคันทั้งขาไปและกลับเลย) เกริ่นมานานแล้วมาไล่ดู Session ที่ผมไปเข้ามาดีกว่า\u003c/p\u003e\n\u003ch2 id=\"keynote-challenges-of-managing-a-complex-project---the-case-study-of-landing-a-rover-on-mars\"\u003e\u003cstrong\u003eKeynote: Challenges of Managing a Complex Project - The Case Study of Landing a Rover on Mars\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"/tpse-conference-2013-1-keynote/1461184_10202545868946308_1266542530_n_hu_cbaa845ac71aa39f.webp\"\n       srcset=\"/tpse-conference-2013-1-keynote/1461184_10202545868946308_1266542530_n_hu_cbaa845ac71aa39f.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"640\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003cp\u003eSession นี้ถือว่าเป็น Highlight ของงานเลยครับแค่คนพูดนี่ก็สุดๆแล้ว\u003cstrong\u003eDr.Firouz Naderi\u003c/strong\u003eผู้อำนวยการโครงการสำรวจในระบบสุริยะทั้งหมดจาก NASA JPL เรียกได้ว่าตั้งแต่ดวงอาทิตย์ยันดาวพลูโต Dr. คนนี้มีเอี่ยวหมดโดยดร.ฟิรุสมาเล่าให้ฟังเกี่ยวกับโครงการสำรวจดาวอังคารที่แกกำลังทำอยู่โดยเริ่มการค่อยๆเกริ่นจากไอเดียภาพรวมของการทำโครงการซักโครงการนึงว่า 1)เราเริ่มจากการมีความฝันแล้ว 2)เราขายฝันจากนั้นแล้วในวันถัดมา 3)เราก็เริ่มจะคิดได้ว่า \u0026ldquo;กูมองโลกในแง่ดีเกินไปแล้วนะ\u0026rdquo; ซึ่งพอผ่านจุดนี้เราจะ 4)เริ่มทำงานหนักขึ้นที่ 60 ชั่วโมงต่อสัปดาห์และ 5)เราก็จะเริ่มเครียดขึ้นอีกเรื่อยๆจากปัญหาต่างๆที่รุมเข้ามาไม่ว่าจะเป็นปัญหาทางเทคนิค, งบหรือแม้กระทั่งกำหนดส่งปัญหาเหล่านี้จะส่งผลให้ 6)เราทำงานหนักขึ้นอีกเป็น 70 ชั่วโมงต่อสัปดาห์ซึ่งเมื่อถึงท้ายที่สุดแล้วไม่มีใครบอกได้ว่า 7)โครงการที่เราทำอยู่จะประสบความสำเร็จ\u0026hellip;.. หรือล้มเหลว\u003c/p\u003e","title":"TPSE CONFERENCE 2013 ตอนที่ 1 : งานอไจล์ที่ไม่มีคำว่าอไจล์ในชื่องาน + KEYNOTE ไปดาวอังคาร"},{"content":"ต่อจาก โพสที่แล้ว เลยนะครับเพื่อไม่ให้เป็นการเสียเวลา\nRobot Framework: Generic test automation framework for acceptance testing and acceptance test-driven development (ATDD) สำหรับ Session นี้ผมถือว่าเป็น Session ที่สนุกที่สุดของงานนี้แล้วโดย Speaker เป็นพี่รูฟ @roofimon โดย Session นี้คนเยอะมากๆเข้ามาแทบไม่ขาดสายจนที่นั่งไม่พอเลยทีเดียวสำหรับ Robot Framework อธิบายง่ายๆคือเป็น Automate test framework ตัวนึงที่ช่วยให้งานของ Tester นั้นง่ายขึ้นแต่ก่อนจะเริ่มนั้นพี่รูฟถามว่า \u0026ldquo;ใครรู้สึกตัวว่าอยู่ผิดห้องมั้ยครับ ?\u0026rdquo; ประมาณ 4-5 รอบเลย\nพี่รูฟเริ่มต้นด้วยการอธิบายคอนเซปของ Requirement ลูกค้าว่าก็เหมือนการสอบสมัยเรียนมหาลัยโดยอาจารย์จะมีโจทย์ที่อลังการงานสร้างที่สุดเท่าที่คิดออกมาให้เราพร้อมกับ\u0026hellip; กระดาษหนึ่งแผ่นหน้าที่ของเราคือเขียนคำตอบไปให้มันตรงกับความต้องการของอาจารย์ให้มากที่สุดโดยพี่รูฟยกตัวอย่างเช่นถ้าสมมติอาจารย์เฉลย 80 แล้วเราตอบ 160/2 แทนที่เราจะได้ซักครึ่งคะแนนแต่กลับกลายเป็นว่าเราไม่ได้เลย \u0026ldquo;สัส มึงทำผิด !!\u0026rdquo; พี่รูฟยังยกตัวอย่างข้อสอบ Tense ภาษาอังกฤษที่จะมีการ Guideline มาเป็น Passage แล้วให้เราหยอดคำลงไปในช่องว่าง (ซึ่งยังพอมั่วได้แม่นกว่า) ซึ่งถ้าเปรียบเทียบกับ S/W แล้วการที่เรามี Guideline ในการตรวจรับที่ชัดเจนจะทำให้เรามีความสุขกับงานที่ทำมากกว่า\nหลังจากนั้นพี่รูฟพูดถึงบริษัท Odd-e นิดหน่อยอันนี้ผมขอข้ามละกันเพราะไม่เกี่ยวกับเนื้อหาประเด็นต่อไปที่พี่รูฟพูดถึงคือถึงแม้เราจะใช้ Agile มาช่วยในการทำงานแล้วก็ตามเราก็ยังคงเจอปัญหา Requirement แบบนี้อยู่เสมอเนื่องจากเรามักจะคิดว่า \u0026ldquo;สิ่งที่เรารู้เป็นสิ่งที่ลูกค้าอยากได้\u0026rdquo; ทำให้เกิดปัญหาเมื่อถึงตอนจบแล้วลูกค้าจำไม่ได้แล้วตอบเรากลับมาว่า \u0026ldquo;ผมไม่ได้พูดอย่างนั้นนะ\u0026rdquo; ซึ่งพี่รูฟก็ได้ชี้ให้เห็นว่าแท้จริงแล้วนั้นของที่ถูกต้องมันอยู่ในมือของ Tester ไม่ใช่ Programmer แต่เนื่องจาก Programmer เป็น \u0026ldquo;สิ่งมีชีวิตที่คิดว่าตัวเองฉลาดที่สุดในโลก\u0026rdquo; มีความผยองและเป็นอย่างนี้มาหลายชั่วอายุคนปัญหานี้จึงยังเกิดขึ้นอยู่เสมอวิธีแก้คือ ให้ Programmer หา Tester มาเป็นแฟน\u0026hellip; ไม่ใช่ !!! แต่ให้เราเขียน Test ตั้งแต่ขั้น Design กันเลยทีเดียว\nต่อมาพี่รูฟก็ได้พาเราไปรู้จักกับ Acceptance Test Driven Development โดยเริ่มต้นบอกไว้ก่อนเลยว่าเราไม่สามารถจะทำ ATDD ได้ในตอนแรกทั้งหมดทีเดียวซึ่งการทำ Agile ก็จะเข้ามาช่วยในจุดนี้โดยเราจะเลือก Requirement ที่สำคัญที่สุดมาทำก่อนและต้องสามารถทำเสร็จได้ภายใน 2 อาทิตย์ด้วย (ตรงนี้ฮามากเพราะดูเหมือนพี่รูฟจะโดนปรับถ้าเผลอพูดศัพท์เกี่ยวกับ Agile ขึ้นมาแต่ก็มีเหตุผลที่น่าสนใจตามมาว่าเพราะในช่วง 2 สัปดาห์นั้นคนเรายังสามารถจำสิ่งที่ตัวเองพูดได้อยู่) โดยเอามาเข้า Discuss in workshop ซึ่งสามารถทำได้ตรงช่วง Sprint Planning Part 1 โดยใน Workshop นี่คนทั้งหมดที่มีส่วนร่วมจะต้องมาคุยกันแล้วถามไปเรื่อยๆว่าสิ่งที่ลูกค้าอยากได้คืออะไรโดยถ้าเริ่มคุยกันไม่รู้เรื่องพี่รูฟแนะนำว่าให้จบด้วยคำว่า \u0026ldquo;ยกตัวอย่างเช่น\u0026rdquo; เพื่อให้คนที่อธิบายได้จำลองตัวเองไปเป็นคนผู้ใช้งาน (Walkthrough Scenario) ซึ่งผลลัพธ์ที่ได้ออกมาก็คือ Test Scenario หรือตัวอย่าง Scenario ทั้งหมดที่ผู้ใช้ต้องการออกมาเป็นชุดๆเลยนอกจากนั้นแล้วพี่รูฟยังบอกถึงความแตกต่างระหว่างตัวอย่างดีและไม่ดีโดยการเล่าขึ้นมาแบบลอยๆนั้นเทียบไม่ได้กับตัวอย่างแบบ Concrete (ผมก็ไม่รู้จะใช้คำไหนอธิบาย) โดยผู้เล่าจะเล่าออกมาเป็นเหตุการณ์ประมาณว่าเมื่อถึงหน้านี้จะกรอกชื่อ\u0026hellip; กรอกอะไรลงไป\u0026hellip; ได้หน้าจอ\u0026hellip; ถ้าสำเร็จ\u0026hellip; ถ้าไม่สำเร็จ\u0026hellip; เป็นต้น\nหลังจากนั้นแล้วทีมก็จะเอา Test Scenario ที่ได้นี้มาเขียนลงใน Acceptance Criteria ซึ่งเป็นเหมือนเส้นที่คอยวัดว่าของที่เราสร้างตรงกับสิ่งที่ลูกค้าอยากได้หรือยัง (และไว้ป้องกัน Bug ด้วย) ซึ่งการมี Acceptance Criteria นั้นจะช่วยป้องกันไม่ให้ Programmer เขียนโปรแกรมออกทะเลที่มีพายุตั้งเค้าอยู่โดยยกตัวอย่างเช่นการ Login เพื่อเข้าใช้งานเราก็จินตนาการตามไปว่ามี 2 Field คือ Email กับ Password ซึ่งเราก็ได้ฟังตัวอย่างการไล่รายละเอียดของแต่ละ Scenario ไปจนได้ออกมาเป็น Acceptance Criteria ดังตารางข้างล่าง\nซึ่งถ้าเราทำได้กับ Scenario ทั้งหมดความชัดเจนในเป้าหมายของ Programmer ก็จะมากขึ้นด้วยแต่พี่รูฟก็ย้ำกับเราอีกทีว่าเรา \u0026ldquo;ทำแบบนี้ทั้งหมด\u0026rdquo; ไม่ได้โดยต้อง\nเลือกเอางานที่สำคัญที่สุด โดยให้ลูกค้าเลือก งานนั้นต้องเล็กพอจะเสร็จใน 2 สัปดาห์ (1 Sprint) เอามาคุยกันจนได้ Acceptance Criteria แล้วค่อยเริ่มงาน อย่างไรก็ตามการทำแบบนี้พี่รูฟก็ยังบอกว่ามันยังคงเหนื่อยอยู่แต่ \u0026ldquo;เหนื่อยน้อยกว่า\u0026rdquo; ไม่ทำและนอกจากนั้นแล้วจะทำให้ทีมมีโฟกัสที่ชัดเจน, คนทำเสร็จดีใจและลูกค้าได้ของตามต้องการจนมีอารมณ์เลือกของตัวถัดไปที่อยากได้ถูกแต่เนื่องจากงานนี้มีคำว่า Practical อยู่พี่รูฟจึงยังยกตัวอย่างอีกว่าถ้าระบบเล็กๆนั้นไม่มีปัญหาที่จะใช้บริการของ Tester ในแบบ Monkey see, monkey do ซึ่งเป็นงานที่น่าเบื่อและแพงมากการที่เราเอากระบวนการ Automate มาช่วยในจุดนี้ไม่ได้เป็นการลดภาระของ Tester แต่จะทำให้เกิด Value ในตัว Tester มากกว่าเดิมเพราะขยับมาก่อน Implement และเป็นการ Preventive Mode หรือกันไว้ดีกว่าแก้นั่นเองทำให้ Tester สามารถเอาเวลาไปทำประโยชน์อย่างอื่นได้มากขึ้นด้วย\nสำหรับ Tools นั้นแน่นอนว่าจั่วหัวไว้แล้วว่า Robot Framework แต่พี่รูฟเกริ่นด้วย Selenium ซึ่งเป็น Tool ที่ใครทำ UX Test ต้องเคยได้ยินแน่นอนซึ่งผมก็เพิ่งรู้ตอนนี้เองว่า Selenium มันมีข้อเสียตรงที่จะเขียน Script เพื่อสั่งมันจริงๆได้ยากมากถึงแม้จะรองรับหลายภาษาก็ตามโดยวิธีแก้ปัญหานี้คือหลายๆคนพยายามจะเขียน Script มาครอบ Selenium อีกชั้นนึงเพื่อให้ใกล้กับภาษาคนที่ฝั่ง Business อ่านออกมากขึ้น\nมาต่อที่ Robot Framework ตัวนี้ก็เป็นตัวที่สามารถครอบ Selenium ดังที่กล่าวไปแล้วโดยมันจะทำหน้าที่ในการแปลง Acceptance Criteria หรือ Test Scenario ให้ไปเป็น Keyword ซึ่งเราสามารถเขียนมันออกมาเป็น HTML Table ธรรมดาๆได้โดย 1 Scenario จะแทนด้วย 1 Table นั้นเองซึ่งข้อดีที่มันเป็น HTML ธรรมดานั้นที่ก็คือเราสามารถใช้ VCS เช่น Git มาควบคุมมันได้ด้วย\nจากตารางจะเห็นได้ว่า Step ที่อยู่ใน Test Case นั้นมันเป็นภาษาที่เราให้ใครอ่านก็รู้เรื่อง ซึ่งเป็นภาษา Level บนสุดของการเขียน Test แล้ว (พี่รูฟยังบอกอีกว่ามี Tool บางตัวเขียนเป็นภาษาได้เลย เอาเข้าไป !!) ในส่วนของ Robot Architecture นั้นพี่รูฟอธิบายว่าตัว Test Scenario ที่เป็นตารางของเรานี้จะอยู่ชั้นบนสุดซึ่งก็คือ Test Data ซึ่งในชั้น Robot Framework จะเป็นตัวไปเรียก Library ให้ไปสั่ง Tool เช่น Selenium ในการทำงาน โดยข้อดีของ Robot ยังไม่จบแค่นี้ สำหรับอะไรที่เราทำซ้ำๆ เราสามารถดึงมันออกมาแยกเก็บไว้ได้แล้วเรียกใช้ทีหลังสิ่งนั้นเรียกว่า Resource\nช่วงท้ายๆ ก่อนถามตอบพี่รูฟพูดถึง Specification Pyramid (จากหนังสือ Agile Testing) ซึ่งหาภาพประกอบได้ยากมากประมาณว่าในส่วนของ Rule กับ Workflow นั้น Tester จะสามารถทำตรงนี้ได้เก่งมาก (ส่วนบนของพีระมิด) และในส่วนของ Technical Activity ซึ่งก็คือฐานของพีระมิดนั้นก็เป็นส่วนที่ Programmer ต้องทำให้สอดรับกันพอดี (Unit Test) อีกเรื่องคือ Principle of Symmetric Change ซึ่งเขียนไว้ว่า One small change in the business domain results in one small change in software. ซึ่งพี่รูฟก็บอกว่าในสมัยอดีตนั้นจริงอยู่แต่ปัจจุบันมันกลับด้านกันแล้ว!!\nปล.ผมว่ามันเริ่มยาวเกินไปละสำหรับ 1 Session ไม่ได้สรุปแต่เก็บเต็มเม็ดเต็มหน่วยเลย\u0026hellip;\nOriginal post at: https://yothinix.blogspot.com/2013/11/tpse-conference-2013-2-robot-framework.html\n","permalink":"https://yothinix-com.pages.dev/tpse-conference-2013-2-robot-framework/","summary":"\u003cp\u003eต่อจาก \u003ca href=\"/tpse-conference-2013-1-keynote/\"\u003eโพสที่แล้ว\u003c/a\u003e เลยนะครับเพื่อไม่ให้เป็นการเสียเวลา\u003c/p\u003e\n\u003ch2 id=\"robot-framework-generic-test-automation-framework-for-acceptance-testing-and-acceptance-test-driven-development-atdd\"\u003eRobot Framework: Generic test automation framework for acceptance testing and acceptance test-driven development (ATDD)\u003c/h2\u003e\n\u003cp\u003eสำหรับ Session นี้ผมถือว่าเป็น Session ที่สนุกที่สุดของงานนี้แล้วโดย Speaker เป็นพี่รูฟ \u003cstrong\u003e@roofimon\u003c/strong\u003e โดย Session นี้คนเยอะมากๆเข้ามาแทบไม่ขาดสายจนที่นั่งไม่พอเลยทีเดียวสำหรับ Robot Framework อธิบายง่ายๆคือเป็น Automate test framework ตัวนึงที่ช่วยให้งานของ Tester นั้นง่ายขึ้นแต่ก่อนจะเริ่มนั้นพี่รูฟถามว่า \u0026ldquo;\u003cem\u003eใครรู้สึกตัวว่าอยู่ผิดห้องมั้ยครับ ?\u003c/em\u003e\u0026rdquo; ประมาณ 4-5 รอบเลย\u003c/p\u003e\n\u003cp\u003eพี่รูฟเริ่มต้นด้วยการอธิบายคอนเซปของ Requirement ลูกค้าว่าก็เหมือนการสอบสมัยเรียนมหาลัยโดยอาจารย์จะมีโจทย์ที่อลังการงานสร้างที่สุดเท่าที่คิดออกมาให้เราพร้อมกับ\u0026hellip; กระดาษหนึ่งแผ่นหน้าที่ของเราคือเขียนคำตอบไปให้มันตรงกับความต้องการของอาจารย์ให้มากที่สุดโดยพี่รูฟยกตัวอย่างเช่นถ้าสมมติอาจารย์เฉลย 80 แล้วเราตอบ 160/2 แทนที่เราจะได้ซักครึ่งคะแนนแต่กลับกลายเป็นว่าเราไม่ได้เลย \u0026ldquo;\u003cstrong\u003eสัส มึงทำผิด !!\u003c/strong\u003e\u0026rdquo; พี่รูฟยังยกตัวอย่างข้อสอบ Tense ภาษาอังกฤษที่จะมีการ Guideline มาเป็น Passage แล้วให้เราหยอดคำลงไปในช่องว่าง (ซึ่งยังพอมั่วได้แม่นกว่า) ซึ่งถ้าเปรียบเทียบกับ S/W แล้วการที่เรามี Guideline ในการตรวจรับที่ชัดเจนจะทำให้เรามีความสุขกับงานที่ทำมากกว่า\u003c/p\u003e\n\u003cp\u003eหลังจากนั้นพี่รูฟพูดถึงบริษัท \u003cstrong\u003eOdd-e\u003c/strong\u003e นิดหน่อยอันนี้ผมขอข้ามละกันเพราะไม่เกี่ยวกับเนื้อหาประเด็นต่อไปที่พี่รูฟพูดถึงคือถึงแม้เราจะใช้ Agile มาช่วยในการทำงานแล้วก็ตามเราก็ยังคงเจอปัญหา Requirement แบบนี้อยู่เสมอเนื่องจากเรามักจะคิดว่า \u0026ldquo;\u003cem\u003eสิ่งที่เรารู้เป็นสิ่งที่ลูกค้าอยากได้\u0026rdquo; ทำให้เกิดปัญหาเมื่อถึงตอนจบแล้วลูกค้าจำไม่ได้แล้วตอบเรากลับมาว่า \u0026ldquo;ผมไม่ได้พูดอย่างนั้นนะ\u003c/em\u003e\u0026rdquo; ซึ่งพี่รูฟก็ได้ชี้ให้เห็นว่าแท้จริงแล้วนั้นของที่ถูกต้องมันอยู่ในมือของ Tester ไม่ใช่ Programmer แต่เนื่องจาก Programmer เป็น \u0026ldquo;\u003cstrong\u003eสิ่งมีชีวิตที่คิดว่าตัวเองฉลาดที่สุดในโลก\u003c/strong\u003e\u0026rdquo; มีความผยองและเป็นอย่างนี้มาหลายชั่วอายุคนปัญหานี้จึงยังเกิดขึ้นอยู่เสมอวิธีแก้คือ \u003cstrong\u003eให้ Programmer หา Tester มาเป็นแฟน\u003c/strong\u003e\u0026hellip; ไม่ใช่ !!! แต่ให้เราเขียน Test ตั้งแต่ขั้น Design กันเลยทีเดียว\u003c/p\u003e","title":"TPSE CONFERENCE 2013 ตอนที่ 2 : ROBOT FRAMEWORK"},{"content":"ก็เป็นตอนที่ 3 แล้วสิ่งที่ผมจะมาพูดถึงในวันนี้คือหนึ่งในเรื่องที่ตัดสินใจยากที่สุดตั้งแต่ตอนเริ่มทำ Project I แล้วคือการหา Project Management Tool ครับย้อนกลับไปในเดือนกรกฎาคมปี 2013 เป็นช่วงเวลาที่โปรเจ็คเริ่มตั้งไข่หลังจากส่ง Proposal และได้รับการอนุมัติแล้วในช่วงเวลานั้นผมยังคงยอมรับว่าผมยังคงใหม่กับ Agile Practice มาก (จนถึงตอนนี้ก็ยังยอมรับว่ายังใหม่อยู่) และสิ่งที่มือใหม่ Agile มักจะทำกันจากที่ผมสังเกตมาหลายคนที่ศึกษาเองคือหาเครื่องมือที่เหมาะสมกับตัวเองและทีมเพื่อที่จะใช้ Agile ได้อย่างสมบูรณ์แบบ (แต่ผมก็ไม่ได้บอกว่าวิธีการนี้เป็นวิธีการศึกษาที่ดีนะครับจริงๆพอมามองย้อนกลับไปผมน่าจะไปศึกษาแนวคิดให้มันแน่นกว่านี้แต่อย่างว่ามือใหม่มักจะตื่นเต้นกับ Tools มากกว่าหลักการจริงๆเสมอ)\nRelease Backlog แรกสุดที่ทำ มีแค่ Excel\nผมเริ่มต้นการศึกษาหลักการนี้จากงาน Agile Thailand 2013 แล้วต่อยอดมาอ่านAgile SamuraiและScrum Primerซึ่งสุดท้ายแล้วก็เลือกที่จะนำเอาแนวคิด Scrum มาใช้ในการทำ Project อย่างที่ท่านๆได้เคยเห็นไปแล้วในบล็อกตอนก่อนๆเครื่องมือที่ใช้ในช่วงแรกๆนั้นมีแค่ Excel, Post-It และ Whiteboard แค่นั้นในการทำ Backlog Grooming ครั้งแรกซึ่งการคุยกันครั้งแรกสามารถแตก User Story บางเรื่องที่ไม่เคยคิดว่าจะใหญ่ออกเป็นก้อนเล็กๆได้และสามารถคิด Feature เพิ่มขึ้นมาได้หลายอย่างด้วยพอเรียงลำดับความสำคัญกันเสร็จผมและทีมก็ประสบปัญหาทันทีคือจะเอามันไปไว้ตรงไหนให้ดูได้ตลอด Story ในเวลานั้นก็เลยย้ายไปติด Product Backlog ไว้มุมห้องมุมหนึ่งซึ่งสรุปในเวลาต่อมาไม่นานว่าแทบไม่มีใครดูเลยเพราะมันติดกันอัดแน่นมากผมจึงเริ่มมองหาเครื่องมือใหม่อีกครั้ง\nโชคไม่ดีที่หลังจากนั้นไม่นานผมและทีมตัดสินใจที่จะเปลี่ยนหัวข้อการทำ Project ใหม่สิ่งที่ส่งผลตามมาคือทุกอย่างที่เราเคยทำไว้ก่อนหน้านี้ถือว่าเซตซีโร่, ยกเข่งทำใหม่หมดช่วงนั้นหนึ่งในเรื่องพื้นฐานที่สุดที่ต้องเปลี่ยนคือเราต้องการ Tool ที่ทุกคนสามารถที่จะเข้าไปดูความคืบหน้าของแต่ละคนได้และสามารถรองรับแนวคิด Scrum ที่เรากำลังยึดถือกันอยู่ได้ความต้องการแค่นี้หลังจากนั้นเป็นการหาข้อมูลและผมค้นพบว่ามีการถกเถียงกันอย่างกว้างขวางในเรื่องของ Tools ในสังคม Agile หลายๆที่ไม่ว่าจะเป็นใน Stack overflow, ตามบล็อกอิสระทั่วไปหรือแม้กระทั่งในกลุ่มAgile66เองแต่นอกจากแนวคิดที่ใช้แค่ Post-It กับกระดานบอร์ดนั้น Tools ที่ใช้มีหลักๆที่คนแนะนำอยู่ไม่กี่ตัวหนึ่งในนั้นคือ Trello\nTrelloเป็นหนึ่งในเครื่องมือที่ใช้ในการทำ Agile ได้ง่ายที่สุดและเร็วที่สุดเพราะแทบจะไม่มีอะไรเลยนอกจาก Kanban board ซึ่งเอาเข้าจริงก็ตอบโจทย์ผมได้ในระดับนึงเลยทีเดียวความสามารถในการปรับแต่งตัวโครงสร้างของบอร์ดให้รองรับกับรูปแบบของทีมถือว่าเป็นจุดเด่นอย่างหนึ่งที่ผมยอมรับเลยว่า Trello ทำออกมาได้ดีมาก (แต่ก็อย่าลืมว่าเครื่องมือส่วนใหญ่หลายๆตัวก็สามารถปรับแต่งในจุดนี้ได้) ผมยอมรับตามตรงว่าไม่ได้มีโอกาสสัมผัส Trello อย่างจริงจังมากเพราะในตอนนั้นผมคิดแต่เพียงว่าในเมื่อมันเป็นแค่ Board และตัวอื่นๆก็สามารถทำได้หมดทำไมไม่หาเครื่องมือที่มันครบเครื่องกว่านี้หล่ะ (เป้าหมายจริงๆคืออยากได้เครื่องมือที่วาด Burndown Chart ให้ได้พอมาคิดดูตอนนี้ทำไมแนวคิดผมโคตรเด็กเลยแหะ)\nจริงๆผมมีเครื่องมือที่อยากพูดถึงอีกหลายตัวก่อนจะเข้า TFS ซักทีตัวสุดท้ายที่ผมอยากจะพูดถึงก่อนเราจะเข้าเรื่องหลักที่จะมาพูดกันในวันนี้คือAsanaครับ Asana เป็น Project Management Tool ที่เพิ่งเปิดตัวได้ไม่นานเป็นผลงานของ Dustin Moskovitz (Facebook Co-founder) และทีมงานซึ่งด้วยเหตุนี้ทำให้เครื่องมือตัวนี้ออกจะโด่งดังอยู่ซักหน่อยจุดเด่นจริงๆของ Tool ตัวนี้คือ Task Management โดยหลักการแล้วแทบไม่แตกต่างจากBasecampหรือตัวอื่นๆมากนักแต่ที่ประทับใจที่สุดก็คงจะเป็น UX ที่วืดวาดๆได้ถูกใจวัยรุ่นเป็นอย่างมากรวมถึงระบบส่ง email ในการแจ้งเตือน Task ที่ใกล้จะเสร็จก็พูดตามตรงว่าโคตรน่ารำคาญแต่ได้ผลมากระดับนึงอย่างไรก็ตามผมมองว่าสำหรับทีมผมการที่เราไม่เลือกใช้เครื่องมือตัวนี้มีเพียงเหตุผลเดียว \u0026ldquo;มันไม่มีบอร์ดงาน\u0026rdquo;\nMicrosoft Team Foundation Serviceมาเตะตาผมตอนที่ผมคิดจะเริ่มไปใช้ Microsoft Project แต่ด้วยเหตุผลบางอย่างผมมองว่า Microsoft Project เป็นเครื่องมือที่โบราณและอุ้ยอ้ายเกินกว่าที่จะทำ Agile ได้ผมเลยผ่านมาหา TFS อีกรอบจริงๆแล้วนี่ไม่ใช่ครั้งแรกที่ผมคิดจะใช้ TFS ตอนช่วงระหว่างฝึกงานภาคฤดูร้อนผมเคยมีแนวคิดที่จะใช้ TFS ในการจัดการงานที่ทำในช่วงฝึกงานอยู่พักนึง (เนื่องจากตอนนั้น Scale งานเริ่มใหญ่ขึ้นเรื่อยๆ) แต่การที่ในช่วงฝึกงานยังมีความรู้ในแนวคิดของ Agile และ Scrum อยู่น้อยมากทำให้ความพยายามในการใช้งานครั้งแรกไม่ประสบความสำเร็จซักเท่าไรและผมก็ลืมมันไปจนกระทั่งอย่างที่บอกลอยมาเตะตาอีกครั้งต้องสารภาพไว้ก่อนว่าผมได้ใช้ TFS แค่ในส่วนของ Work Management แค่นั้นในส่วนของ Source code management และ Build/Test Server ผมไม่ได้แตะมันเลย (เนื่องจากโปรเจ็คของทีมผมเป็น PHP-Based)\nเนื่องจากทีมของผมเป็นทีมที่โคตรมีขนาดเล็ก (มีกันอยู่ 3 คน) ทำให้สามารถใช้โปรโมชั่นฟรีของเครื่องมือหลายๆตัวได้ TFS เองก็เป็นหนึ่งในนั้นโดยมี Free Plan ไว้จำกัดที่ไม่เกิน 5 User ตัว TFS เองมาพร้อมกับ Process Template ทั้ง Agile และ CMMI โดย Template ที่ทีมผมเลือกใช้คือ Microsoft Visual Studio Scrum 3.0 ซึ่งตอบโจทย์ผมได้พอดีจากที่กล่าวไปในตอนต้นว่าผมใช้ Scrum เป็นแนวคิดหลักในการทำงานของทีมเครื่องมือที่ TFS มีมาให้พูดจริงๆก็เรียกได้ว่าครบครันพอเพียงตรงตามความต้องการหลายๆอย่างไม่ว่าจะเป็นตาราง Backlog ตั้งแต่ในระดับ Release จนถึงในระดับ Sprint, Cumulative Flow, เครื่องมือวัด Team Velocity และ Board ในการทำงานพร้อม Burndown Chart ที่ไว้คอยจับคนอู้ได้อย่างชัดเจน\nSprint Backlog ช่วงท้ายๆ Project I\nในช่วงเดือนกันยายนปี 2013 ซึ่งเป็นช่วงที่เข้มข้นที่สุดของ Project I เลยก็ว่าได้ผมยอมรับเลยว่า TFS มีส่วนช่วยมากกว่า 50% ในการจัดการงานให้ทีมของผมสามารถทำสำเร็จลุล่วงไปได้จนถึงการสอบปัญหาที่เจอในช่วง Sprint แรกคือทีมผมไม่สามารถประเมินเวลาการทำงานได้อย่างต่อเนื่องอาจจะยังเป็นเพราะยังไม่ชินกับการทำงานในแบบนี้ (ลากจาก To-dos-\u0026gt;Done ทีเดียวตอนงานเสร็จ) ทำให้พอจบ Sprint 1 ต้องมาคุยกันอีกรอบว่าต้องขยันอัพเดทบอร์ดกันมากกว่านี้และสิ่งที่เป็นปัญหาอีกอย่างคือการไม่ได้กำหนด Definition of Done ของหลายๆงานที่สร้างกันไว้ทำให้คำว่าเสร็จของแต่ละคนในทีมความหมายไม่ตรงกันและสุดท้ายมันก็ไม่เสร็จ (ในความหมายของทุกคน (แต่อาจจะเสร็จในความหมายของบางคน)) ซึ่งนี่ก็เป็นอีกจุดหนึ่งที่ทีมผมพยายามปรับปรุงกันตลอด 4 Sprint\nอย่างไรก็แล้วแต่สิ่งสำคัญที่สุดสิ่งหนึ่งที่ได้เรียนรู้หลังจากการทำงานใน Project I ผ่านไปคือยิ่งทีมนั่งทำงานด้วยกันมากเท่าไรโอกาสที่ Flow การทำงานมันจะไหลไปได้เร็วโดยไม่ขลุกขลักก็มีสูงขึ้นมากเนื่องจากในช่วงแรกๆจนถึงกลางๆของการทำ Project I ผมเป็นคนเดียวในทีมที่แยกออกมานั่งทำงานจากคนละที่กับทีมทำให้เจอปัญหาสำคัญคือการสื่อสารไม่เข้าใจกันและทำให้เกิดความไม่เข้าใจกันในเรื่อง Definition of Done อย่างที่กล่าวไปแล้วขอกล่าวไว้ก่อนว่าผมไม่ได้บอกว่าการทำงานแบบ Remote เป็นสิ่งที่ไม่ดีแต่การจะทำงานแบบนั้นได้มีประสิทธิภาพให้ใกล้เคียงกับการทำงานด้วยกันในที่เดียวกันคือต้องสื่อสารกับทีมให้เคลียร์และไม่ค้างคาตลอดเวลาของการทำ Project ไม่ใช่เพียงเฉพาะช่วงเริ่มต้น (แต่ช่วงเริ่มต้นอาจจะมากหน่อย)\nก็หมดแล้วครับตอนแรกว่าจะมาพูดเรื่อง TFS อย่างเดียวแต่คิดไปคิดมาพูดถึงบริบทอื่นๆไปด้วยน่าจะเห็นเหตุผลมากกว่าว่าทำไมผมถึงมาใช้ TFS และสิ่งต่างๆที่ผมกล่าวไปในข้างต้นมาจากความคิดเห็นและประสบการณ์ส่วนตัวเกือบทั้งหมดหากเข้าใจผิดพลาดไปประการใดทางผมก็ยินดีรับฟังและปรับปรุงเพื่อความเข้าใจที่ถูกต้องครับ\nปล.Project II ปัจจุบันผมเลิกใช้ TFS แล้วครับด้วยเหตุผลบางอย่าง\u0026hellip;\nOriginal post at: https://yothinix.blogspot.com/2013/11/tde-3-team-foundation-service.html\n","permalink":"https://yothinix-com.pages.dev/tde-w-3-team-foundation-service/","summary":"\u003cp\u003eก็เป็นตอนที่ 3 แล้วสิ่งที่ผมจะมาพูดถึงในวันนี้คือหนึ่งในเรื่องที่ตัดสินใจยากที่สุดตั้งแต่ตอนเริ่มทำ Project I แล้วคือการหา Project Management Tool ครับย้อนกลับไปในเดือนกรกฎาคมปี 2013 เป็นช่วงเวลาที่โปรเจ็คเริ่มตั้งไข่หลังจากส่ง Proposal และได้รับการอนุมัติแล้วในช่วงเวลานั้นผมยังคงยอมรับว่าผมยังคงใหม่กับ Agile Practice มาก (จนถึงตอนนี้ก็ยังยอมรับว่ายังใหม่อยู่) และสิ่งที่มือใหม่ Agile มักจะทำกันจากที่ผมสังเกตมาหลายคนที่ศึกษาเองคือหาเครื่องมือที่เหมาะสมกับตัวเองและทีมเพื่อที่จะใช้ Agile ได้อย่างสมบูรณ์แบบ (แต่ผมก็ไม่ได้บอกว่าวิธีการนี้เป็นวิธีการศึกษาที่ดีนะครับจริงๆพอมามองย้อนกลับไปผมน่าจะไปศึกษาแนวคิดให้มันแน่นกว่านี้แต่อย่างว่ามือใหม่มักจะตื่นเต้นกับ Tools มากกว่าหลักการจริงๆเสมอ)\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/tde-w-3-team-foundation-service/Picture1_hu_6cccca77049c62ab.webp\"\n       srcset=\"/tde-w-3-team-foundation-service/Picture1_hu_6cccca77049c62ab.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"404\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003eRelease Backlog แรกสุดที่ทำ มีแค่ Excel\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eผมเริ่มต้นการศึกษาหลักการนี้จากงาน Agile Thailand 2013 แล้วต่อยอดมาอ่าน\u003ca href=\"http://www.amazon.com/The-Agile-Samurai-Pragmatic-Programmers/dp/1934356581\"\u003eAgile Samurai\u003c/a\u003eและ\u003ca href=\"http://scrumprimer.org/\"\u003eScrum Primer\u003c/a\u003eซึ่งสุดท้ายแล้วก็เลือกที่จะนำเอาแนวคิด Scrum มาใช้ในการทำ Project อย่างที่ท่านๆได้เคยเห็นไปแล้วในบล็อกตอนก่อนๆเครื่องมือที่ใช้ในช่วงแรกๆนั้นมีแค่ Excel, Post-It และ Whiteboard แค่นั้นในการทำ Backlog Grooming ครั้งแรกซึ่งการคุยกันครั้งแรกสามารถแตก User Story บางเรื่องที่ไม่เคยคิดว่าจะใหญ่ออกเป็นก้อนเล็กๆได้และสามารถคิด Feature เพิ่มขึ้นมาได้หลายอย่างด้วยพอเรียงลำดับความสำคัญกันเสร็จผมและทีมก็ประสบปัญหาทันทีคือจะเอามันไปไว้ตรงไหนให้ดูได้ตลอด Story ในเวลานั้นก็เลยย้ายไปติด Product Backlog ไว้มุมห้องมุมหนึ่งซึ่งสรุปในเวลาต่อมาไม่นานว่าแทบไม่มีใครดูเลยเพราะมันติดกันอัดแน่นมากผมจึงเริ่มมองหาเครื่องมือใหม่อีกครั้ง\u003c/p\u003e\n\u003cp\u003eโชคไม่ดีที่หลังจากนั้นไม่นานผมและทีมตัดสินใจที่จะเปลี่ยนหัวข้อการทำ Project ใหม่สิ่งที่ส่งผลตามมาคือทุกอย่างที่เราเคยทำไว้ก่อนหน้านี้ถือว่าเซตซีโร่, ยกเข่งทำใหม่หมดช่วงนั้นหนึ่งในเรื่องพื้นฐานที่สุดที่ต้องเปลี่ยนคือเราต้องการ Tool ที่ทุกคนสามารถที่จะเข้าไปดูความคืบหน้าของแต่ละคนได้และสามารถรองรับแนวคิด Scrum ที่เรากำลังยึดถือกันอยู่ได้ความต้องการแค่นี้หลังจากนั้นเป็นการหาข้อมูลและผมค้นพบว่ามีการถกเถียงกันอย่างกว้างขวางในเรื่องของ Tools ในสังคม Agile หลายๆที่ไม่ว่าจะเป็นใน Stack overflow, ตามบล็อกอิสระทั่วไปหรือแม้กระทั่งในกลุ่ม\u003ca href=\"https://www.facebook.com/groups/agile66/\"\u003eAgile66\u003c/a\u003eเองแต่นอกจากแนวคิดที่ใช้แค่ Post-It กับกระดานบอร์ดนั้น Tools ที่ใช้มีหลักๆที่คนแนะนำอยู่ไม่กี่ตัวหนึ่งในนั้นคือ Trello\u003c/p\u003e","title":"TDE\u0026W (3) :: TEAM FOUNDATION SERVICE"},{"content":"เมื่อหลายวันก่อนมีรุ่นน้องมาถามผมว่าใช้ Tools ตัวนี้ๆ ดีรึเปล่าสำหรับ Project Management ซึ่งผมก็ตอบไปตามทรรศนะและประสบการณ์ และเมื่อวานนี้ก็มีรุ่นพี่ที่รู้จักได้ยกเรื่องคล้ายๆ กันนี้มาพูดอีกครั้ง ผมก็ยังแนะนำไปตามประสบการณ์ที่เคยใช้งานมา พอดีผมได้มีโอกาสอ่านหนังสือ \u0026ldquo;ใช้ความสุขทำกำไร\u0026rdquo; (Delivery Happiness) เป็นเรื่องราวของบริษัทขายรองเท้าออนไลน์ Zappos ซึ่งมีการกล่าวถึง ค่านิยมหลัก 10 ข้อของบริษัท Zappos และเป็นตัวบ่งบอกความเป็นวัฒนธรรมองค์กรของบริษัทนี้ ประเด็นอยู่ที่ว่าผมไปสะดุดกับข้อ 2)เปิดรับและขับเคลื่อนความเปลี่ยนแปลง 4)พร้อมผจญภัย สร้างสรรค์ และเปิดกว้าง และ 10)รู้จักถ่อมตน ทั้ง 3 ข้อนี้ทำให้ผมคิดถึง Agile Manifesto 2 ข้อคือ\nIndividuals and interactions over processes and tools Responding to change over following a plan ในหลักปรัชญาแบบ Zen ได้มีการกล่าวถึงความคิดของผู้เริ่มต้น (Beginner\u0026rsquo;s mind) ไว้ว่า\nในความคิดของมือใหม่ โอกาสมีอยู่มากมาย แต่ในความคิดของมืออาชีพ โอกาสมีอยู่ไม่มากนัก\nมันทำให้ผมหันกลับมามองย้อนดูตัวเองว่าหลายๆ ครั้งที่เราศึกษาอะไรซักอย่างมาอย่างยาวนาน มันมักจะทำให้เรามีความมั่นใจในตัวเองสูงในเรื่องดังกล่าวซึ่งก็เป็นเรื่องดีเพราะมันทำให้เรากล้าที่จะถ่ายทอดไปได้อย่างเต็มที่ แต่บางครั้งมันก็เป็นหลุมพราง (Pitfall) ที่ทำให้เราพลาดที่จะเรียนรู้สิ่งใหม่ๆ และไม่กล้าที่จะเปิดใจลองสิ่งใหม่ๆ เหมือนตอนที่เราเริ่มต้นศึกษามันก็เป็นได้\nความต้องการแต่ละคนนั้นแตกต่างกัน การเลือกใช้ Tools ใดๆ ก็ตามก็ต้องคำนึงถึงจุดนั้นด้วย คุณไม่สามารถจะใช้ Tools ตัวเดียวกันในทีมที่แตกต่างกัน แม้ว่าความแตกต่างนั้นจะน้อยมากก็ตาม สิ่งที่ผู้ถามต้องการกับสิ่งที่ผู้ตอบต้องการบางครั้งก็ไม่ใช่สิ่งเดียวกัน บางทีมอาจจะต้องการเครื่องมือในการประเมิน เพื่อปรับปรุงความสามารถในการทำงานของทีมอย่างต่อเนื่อง, บางทีมต้องการเพียงแค่บอร์ดงานเพื่อจะได้รู้ว่างานทำไปถึงไหนแล้ว สิ่งเหล่านี้คือความแตกต่างของความต้องการในแต่ละทีม ในฐานะผู้ตอบบางครั้งจากประสบการณ์เพียงอย่างเดียวก็ไม่สามารถตอบโจทย์ผู้ถามได้ และสิ่งที่ควรทำก็คือหาความต้องการของทีมและหาเครื่องมือที่ดีที่สุดให้เขาไป ซึ่งบางครั้งสุดท้ายแล้วอาจจะจบลงด้วยการใช้แค่ Post It กับ Whiteboard เกลี้ยงๆ แค่นั้นก็ได้\nAgile Manifesto ข้อแรกระบุไว้อย่างชัดเจนว่า Individuals and Interactions over processes and tools ซึ่งนำผมกลับมาที่คำถามสุดท้ายแล้ว ที่ว่าสิ่งที่เราต้องการคืออะไร ไม่ใช่เพื่อการสื่อสารภายในทีมเหรอ ทำไมต้องมานั่งกังวลว่าเราควรจะใช้ Tools ตัวไหนดีหรือไม่ดี และถ้ามันไม่ดีเราก็ควรจะ Responding to change ไม่ใช่หรือ ตอนนี้ผมว่าผมยึดติดกับอะไรบางอย่างมานานเกินไปแล้ว น่าจะถึงเวลาลองสิ่งใหม่ๆ ดูเผื่อความคิดของมือใหม่ มันจะกลับมาอีกครั้ง\nปล.ที่เขียนเรื่องนี้จุดประสงค์จริงๆ คืออยากจะเตือนสติตัวเองมากกว่า ไม่ได้พาดพิงใครนะครับ\nOriginal post at: https://yothinix.blogspot.com/2013/10/individuals-and-interactions-over.html\n","permalink":"https://yothinix-com.pages.dev/individuals-and-interactions-over-processes-and-tools/","summary":"\u003cp\u003eเมื่อหลายวันก่อนมีรุ่นน้องมาถามผมว่าใช้ \u003cem\u003eTools\u003c/em\u003e ตัวนี้ๆ ดีรึเปล่าสำหรับ \u003cem\u003eProject Management\u003c/em\u003e ซึ่งผมก็ตอบไปตามทรรศนะและประสบการณ์ และเมื่อวานนี้ก็มีรุ่นพี่ที่รู้จักได้ยกเรื่องคล้ายๆ กันนี้มาพูดอีกครั้ง ผมก็ยังแนะนำไปตามประสบการณ์ที่เคยใช้งานมา พอดีผมได้มีโอกาสอ่านหนังสือ \u0026ldquo;\u003cem\u003eใช้ความสุขทำกำไร\u003c/em\u003e\u0026rdquo; (\u003cem\u003eDelivery Happiness\u003c/em\u003e) เป็นเรื่องราวของบริษัทขายรองเท้าออนไลน์ \u003cem\u003eZappos\u003c/em\u003e ซึ่งมีการกล่าวถึง ค่านิยมหลัก 10 ข้อของบริษัท \u003cem\u003eZappos\u003c/em\u003e และเป็นตัวบ่งบอกความเป็นวัฒนธรรมองค์กรของบริษัทนี้ ประเด็นอยู่ที่ว่าผมไปสะดุดกับข้อ 2)เปิดรับและขับเคลื่อนความเปลี่ยนแปลง  4)พร้อมผจญภัย สร้างสรรค์ และเปิดกว้าง และ 10)รู้จักถ่อมตน ทั้ง 3 ข้อนี้ทำให้ผมคิดถึง \u003cem\u003eAgile Manifesto\u003c/em\u003e 2 ข้อคือ\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eIndividuals and interactions over processes and tools\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eResponding to change over following a plan\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eในหลักปรัชญาแบบ \u003cem\u003eZen\u003c/em\u003e ได้มีการกล่าวถึงความคิดของผู้เริ่มต้น (\u003cem\u003eBeginner\u0026rsquo;s mind\u003c/em\u003e) ไว้ว่า\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eในความคิดของมือใหม่ โอกาสมีอยู่มากมาย แต่ในความคิดของมืออาชีพ โอกาสมีอยู่ไม่มากนัก\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eมันทำให้ผมหันกลับมามองย้อนดูตัวเองว่าหลายๆ ครั้งที่เราศึกษาอะไรซักอย่างมาอย่างยาวนาน มันมักจะทำให้เรามีความมั่นใจในตัวเองสูงในเรื่องดังกล่าวซึ่งก็เป็นเรื่องดีเพราะมันทำให้เรากล้าที่จะถ่ายทอดไปได้อย่างเต็มที่ แต่บางครั้งมันก็เป็นหลุมพราง (\u003cem\u003ePitfall\u003c/em\u003e) ที่ทำให้เราพลาดที่จะเรียนรู้สิ่งใหม่ๆ และไม่กล้าที่จะเปิดใจลองสิ่งใหม่ๆ เหมือนตอนที่เราเริ่มต้นศึกษามันก็เป็นได้\u003c/p\u003e\n\u003cp\u003eความต้องการแต่ละคนนั้นแตกต่างกัน การเลือกใช้ \u003cem\u003eTools\u003c/em\u003e ใดๆ ก็ตามก็ต้องคำนึงถึงจุดนั้นด้วย คุณไม่สามารถจะใช้ \u003cem\u003eTools\u003c/em\u003e ตัวเดียวกันในทีมที่แตกต่างกัน แม้ว่าความแตกต่างนั้นจะน้อยมากก็ตาม สิ่งที่ผู้ถามต้องการกับสิ่งที่ผู้ตอบต้องการบางครั้งก็ไม่ใช่สิ่งเดียวกัน บางทีมอาจจะต้องการเครื่องมือในการประเมิน เพื่อปรับปรุงความสามารถในการทำงานของทีมอย่างต่อเนื่อง, บางทีมต้องการเพียงแค่บอร์ดงานเพื่อจะได้รู้ว่างานทำไปถึงไหนแล้ว สิ่งเหล่านี้คือความแตกต่างของความต้องการในแต่ละทีม ในฐานะผู้ตอบบางครั้งจากประสบการณ์เพียงอย่างเดียวก็ไม่สามารถตอบโจทย์ผู้ถามได้ และสิ่งที่ควรทำก็คือหาความต้องการของทีมและหาเครื่องมือที่ดีที่สุดให้เขาไป ซึ่งบางครั้งสุดท้ายแล้วอาจจะจบลงด้วยการใช้แค่ \u003cem\u003ePost It\u003c/em\u003e กับ \u003cem\u003eWhiteboard\u003c/em\u003e เกลี้ยงๆ แค่นั้นก็ได้\u003c/p\u003e","title":"INDIVIDUALS AND INTERACTIONS OVER PROCESSES AND TOOLS"},{"content":"วันที่ 9 ที่ผ่านมาวันคล้ายวันเกิดผมเองครับ แต่ละปีผ่านไปเราถูกบอกว่าเราแก่ขึ้นแล้วนะ ภาระความรับผิดชอบเยอะขึ้นแล้วนะ นั่นคือสิ่งที่เราดำเนินไปและกำลังดำเนินต่อไปทุกวินาทีที่เราใช้ชีวิตอยู่ สิ่งหนึ่งที่ผมเรียนรู้เกี่ยวกับ Agile มาคือ การมองย้อนกลับไปหรือที่ชุมชนชาว Agile เรียกกันว่า Retrospective ไม่ใช่เรื่องเสียเวลาเลย ไม่ใช่การมองอดีตจะเป็นการเสียเวลาอย่างเดียว แต่เป็นการทำให้เรารู้ว่าเราเคยทำอะไรดีๆ มาบ้าง, เคยผิดพลาดตรงไหน และเราจะปรับปรุงมันได้อย่างไร ฟังดูคุ้นๆ ใช่มั้ยครับ Good, Bad, Try นั่นเอง แต่เราจะพูดถึงสิ่งนี้ทีหลัง\nปีที่ผ่านมานับตั้งแต่เดือนตุลาคมปีที่แล้ว ถ้านับเป็นเวอร์ชั่นของ Software คงเรียกได้ว่าเป็น Major Change เลยทีเดียว ลองไล่ดูว่าเกิดอะไรขึ้นบ้าง\nForeign Student Internship Program 2013 @ U.S. Embassy Bangkok เรื่องนี้นับว่าเป็นเรื่องใหญ่ที่สุด จริงๆ แล้วผมตั้งใจจะเขียนเรื่องฝึกงานเต็มๆ ซักตอนนึงเลย แต่ไม่มีโอกาสซักที ตอนนี้เลยเอาแบบย่อๆ ไปก่อน คือ ช่วงประมาณปลายเดือนกันยายน ของปีที่แล้ว เป็นเรื่องธรรมดาของนักศึกษาปี 3 ทีต้องเริ่มหาที่ฝึกงานแล้ว ซึ่งจริงๆ ในตอนนั้นผมก็เล็งไว้หลายที่มาก แต่จนแล้วจนรอดก็ยังไม่ได้สมัครที่ไหน โครงการ FNSIP2013 ผมรู้จักจากคนใกล้ตัวนี้เอง ซึ่งบอกตามตรงว่าไม่เคยคิดว่าจะมีโปรแกรมแบบนี้อยู่ในโลก อาจจะเป็นเพราะการที่เราเรียนในสายวิศวกรรมศาสตร์ ทำให้ไม่ค่อยสนใจ การฝึกงานในองค์กรอะไรแบบนี้นัก เพราะส่วนใหญ่มักมุ่งไปแต่เอกชนอย่างเดียว\nในเวลานั้นตอนแรกผมยื่นสมัครไปเฉยๆ ไม่เคยคิดเลยว่าจะติดเพราะว่าเกรดไม่ถึงแต่แรก แค่ยื่นไปเฉยๆ หลังจากนั้นผมก็ไม่ได้คิดถึงมันอีก จนไปสมัครฝึกงานกับบริษัทอีก 2-3 แห่งจนได้ที่ฝึกงานแน่ๆ แล้ว ปลายเดือนกุมภาพันธ์ปีนี้ ผมได้รับจนหมายตอบกลับจากทางสถานทูตสหรัฐฯ ว่าตอบรับเข้าฝึกงานแล้ว ช่วงเวลานั้นเป็นช่วงเวลาการตัดสินใจที่ยากลำบากที่สุดครั้งนึงในชีวิต เพราะผมต้องเลือกระหว่างไปฝึกงานในบริษัทที่ตรงตามสายงานที่ถนัดและอยากทำ (ในตอนนั้น) จริงๆ กับสถานทูตสหรัฐฯ ซึ่งเป็นเหมือนดินแดนลับแลในเวลานั้น เพราะผมไม่รู้อะไรเลย หลังจากปรึกษากับหลายๆ คนผมก็ตัดสินใจเลือกที่นี่ครับ\nผมพูดถึงเรื่องงานที่ทำที่นั่นไม่ได้มาก แต่บอกได้เลยว่าผมไม่เคยเสียใจเลยที่ได้เลือกฝึกงานที่นี่ ช่วงเวลานั้นผมได้รู้จักกับคนดีๆ เก่งๆ หลายคนมากซึ่งการได้เจออะไรแบบนั้นทำให้ผมรู้สึกตัวลีบลงทันที (อย่างที่บอกแต่แรกว่าเกรดผมไม่ถึงเกณฑ์สมัครด้วยซ้ำ) แต่พอรู้จักกันจริงๆ ถึงได้เริ่มรู้ว่าแต่ละคนที่โครงการคัดเลือกมาจะมีความพิเศษและแตกต่างกันไป ตามแต่ละแผนกที่แต่ละคนไปทำ ซึ่งข้อสำคัญคือ ผมเป็นวิศวฯ คนเดียวในรุ่นที่ฝึกงานด้วยกัน เป็นคนเดียวของมหาลัยตัวเองที่มาฝึกที่นี่ ผมอาจจะไม่พิเศษแต่อย่างน้อยแตกต่างกว่าชาวบ้านแน่นอน\nการที่ผมไม่ได้ทำการในสายงานที่ถนัด (System Admin) แต่มาทำงานที่นี่เปลี่ยนผมให้กลับมารักการเขียนโปรแกรมอีกครั้ง แม้จะไม่ได้เขียนโปรแกรมจริงๆ มากมายก็ตาม แต่การได้อยู่ท่ามกลางโปรแกรมเมอร์กับเทสเตอร์ที่มีประสบการณ์หลายปี มันทำให้ทัศนคติเกี่ยวกับอาชีพนี่ของผมเปลี่ยนไปเลย และเมื่อจบการฝึกงานที่นี่ในเดือนพฤษภาคมที่ผ่านมาผมรู้ตัวเลยว่าผมอยากจะทำประกอบอาชีพอะไรในอนาคต\nAgile Thailand 2013 ถ้าการฝึกงานยังทำให้ผมชัดเจนในความชอบเขียนโปรแกรมมากแค่ไหน งาน Agile Thailand 2013 ที่จัดขึ้นหลังจากผมฝึกงานได้ไม่นาน ก็เป็นตัวช่วยตอกย้ำที่ดีว่าโลกของ Programmer มันไม่ได้มีแค่การเขียนโปรแกรมแต่เพียงอย่างเดียว ผมจำไม่ได้แล้วว่าผมรู้จักกับงานนี้ได้ไง แต่ก็เป็นอีกงานหนึ่งที่ผมไปแล้วไม่ผิดหวังเลย\nจริงๆ ผมน่าจะเคยพูดไปในบางเอนทรี่ก่อนหน้านี้แล้วว่าผมรู้จัก Agile มาก่อนงานนี้แล้ว แต่นั้นก็เป็นเพียงแค่ผิวและผมเห็นว่ามัน \u0026ldquo;ดี\u0026rdquo; แต่พอไปงานนี้ผมถึงกับหลงรักมัน มันไม่ใช่แค่ขั้นตอนการทำงานให้เสร็จ (Getting things done) แต่มันคือ จิตวิญญาณของการทำงานให้เสร็จ และผมเห็นภาพจากหลาย Session เลยว่า สิ่งที่เราเรียนในระดับมัธยมและมหาลัย เกี่ยวกับ Programming มันเป็นแค่ Core 20% ซึ่งก็คือ การเขียนโปรแกรม แต่อีก 80% ที่เหลือไม่ว่าจะเป็น Project Management Workflow, Continuous Integration และการ Test หลายๆ แบบอะไรเหล่านี้ มันทำให้ผมรู้สึกว่าการเป็นโปรแกรมเมอร์มันเท่ห์ และเราสามารถทำงานได้มีประสิทธิภาพจริงๆ มากกว่ามานั่งเถียงกันว่า \u0026ldquo;ก็โค้ดของเมิงมัน Error อ่ะ\u0026rdquo; อะไรประมาณนี้\nProject I นอกเหนือจากเรื่องฝึกงานแล้ว สิ่งหนึ่งที่บังคับให้เราต้องมีความรับผิดชอบและทำตัวเป็นผู้ใหญ่มากขึ้นก็คือ Project ครับ สิ่งที่นักศึกษาวิศวกรรมศาสตร์แทบทุกคนต้องเจอ ตอนเริ่มต้นปี 4 ใหม่ๆ ผมยังไม่มีข้อสรุปที่แน่นอนนักว่าจะทำ Project เรื่องอะไร มันเป็นเรื่องที่ตัดสินใจยากลำบากอีกเรื่องหนึ่งในการมีไอเดียหลายไอเดียแล้วต้องประเมินว่าไอเดียไหนที่เราสามารถทำเสร็จได้จริงภายในหนึ่งปี ซึ่งไม่ใช่แค่ตัวแปรเวลาเพียงอย่างเดียวเท่านั้นส่งผลถึงงาน แต่รวมถึงความสามารถของตัวเองและเพื่อนร่วมทีมอีกด้วย\nเวลา 4 สัปดาห์แรกหลังจากยื่นหัวข้อแรกไป ผมมั่นใจมากกว่าต้องทำได้ เพราะผมมีเครื่องมือในการทำ Project ชั้นดีซึ่งก็คือ Agile แต่พอเข้าสัปดาห์ที่ 5 ผมรู้เลยว่าผมไม่สามารถทำมันให้เสร็จได้ภายใน 1 ปี จริงๆ แล้วรายละเอียดเรื่องของ Project สามารถอ่านได้อย่างละเอียดใน Change ตอนที่ 1 และ Change ตอนที่ 2 ซึ่งเขียนขึ้นหลังช่วงเวลาที่ผมเปลี่ยน Project ใหม่\nตอนนี้ผมมีความสุขดีครับกับ Project ปัจจุบัน แต่สิ่งหนึ่งที่ผมได้เรียนรู้เกี่ยวกับมันคือ การล้มเหลวไม่ใช่ทางเลือกที่แย่ที่สุด แต่ความกล้าที่จะบอกว่าตัวเองล้มเหลวในสิ่งที่ตัวเองทำนั้นต่างหากเป็นเรื่องที่ดีที่สุด เพราะถ้าผมไม่ยอมรับว่าผมล้มเหลวแล้วดันทุรังต่อไป ตอนนี้ผมอาจจะไม่รู้สึกดีอย่างที่เป็นอยู่ก็เป็นได้ และนอกจากนั้นแล้วยังต้องขอบคุณทีมโปรเจ็ค ที่ซึ่งถ้าไม่มีพวกเขาพร้อมกับความเปิดใจรับ Agile เข้าไป ผมก็ไม่สามารถทำงานนี้ให้สำเร็จลงไปได้\nChance พอเราใกล้จะเรียนจบ พอเราสั่งสมประสบการณ์และความสามารถมาตลอด 3 ปีในมหาลัย ปีนี้เป็นปีที่ผมบอกได้เลยว่าเป็นปีที่มีโอกาสเข้ามามากที่สุดในชีวิต ในหลายๆ รูปแบบที่แตกต่างกัน ซึ่งผมอาจจะไม่สามารถบอกได้ตรงๆ ว่ามันคืออะไร แต่สิ่งหนึ่งที่ผมได้เรียนรู้เกี่ยวกับมันคือ ผมเป็นคนที่จะไม่ทิ้งโอกาสถ้ามันมาถึงตรงหน้าแล้ว แต่ก็ไม่รั้งโอกาสจากคนอื่น ถ้าผมรู้ตัวแล้วว่าผมทำมันไม่ได้จริงๆ\nจริงๆ แล้วที่ผมจะมีพูดวันนี้หลักๆ ไม่ได้เกี่ยวข้องกับที่พูดมาตั้งแต่แรกเลย จุดมุ่งหมายหลักของเอนทรี่นี้คือผมต้องการจะกำหนดเป้าหมายให้ตัวเองครับ จริงๆ ผมวางแผนจะทำอะไรแบบนี้มาหลายปีแล้ว แต่พอผ่านวันสำคัญไปนานๆ ความตั้งใจในตอนแรกมันก็จะลดน้อยลงจน ผมลืมมันไปในที่สุด แต่ปีนี้ผมไม่ลืมแล้วครับ ผมได้ลิสต์เป้าหมายของผมที่ต้องทำให้เสร็จในปีนี้ไว้แล้ว ดังต่อไปนี้\n1 Blog entry per week ผมเคยเป็นคนที่ชอบการเขียนมากครับ ผมเขียน Blog ครั้งแรกตอนอยู่ ม.2 และก็ยังคงเขียนมาตลอด แต่สิ่งหนึ่งที่เปลี่ยนไปคือ ผมเขียนมันน้อยลงครับ อาจเป็นเพราะเรามี Facebook, Twitter ทำให้การเขียนของเราเกิดขึ้นทุกวันจนเราไม่รู้สึกว่าเราจะเขียนอะไรอีกต่อไป ทั้งๆ ที่จริงๆ แล้วมันมีเรื่องให้เราเขียนยาวๆ ได้มากกว่าใน Facebook ที่หลายๆ คนมองว่ามันเป็นการสร้างภาพเสมอ\nจริงๆ โครงการนี้ผมเริ่มมาซักพักแล้วด้วยการบังคับตัวเองให้เขียนเป็นซีรีย์ ข้อดีของการเขียนเป็นซีรีย์คือ เราไม่ต้องคิดหัวข้อใหม่ให้มันมากเราก็มีอะไรให้เขียนได้เสมอ ตัวอย่างของซีรีย์ที่ได้เริ่มไว้แล้วตอนนี้มี 2 โครงการคือ Change ที่กำลังจะจบในเร็วๆ นี้และต่อด้วยซีรีย์ใหม่ที่พูดถึง Project II ในภาพรวมทั้งหมด อีกโครงการหนึ่งคือ Team Development Environment \u0026amp; Workflow (TDE\u0026amp;W) ซึ่งก็คือเรื่องเกี่ยวกับการทำงานใน Project เช่นเดียวกัน แต่ในซีรีย์นี้จะลงลึกในเนื้อหาของ Technical, Workflow และ Project Management มากกว่าก็ต้องดูไปว่าจะทำได้จริงมากน้อยแค่ไหน\nBook list มีคนเคยบอกไว้ว่าการที่เราจะเขียนได้มาก เราก็ต้องอ่านมากเช่นกัน ผมมีหนังสือ List ไว้ว่าอยากจะอ่านจบภายในปีนี้ หรือถ้าให้ดีภายในปีใหม่ที่จะถึงนี้เลย (ระยะเวลาประมาณ 3 เดือน) คือ Code Clean, Agile Samurai, Pro git และ Ruby on Rails Tutorials ซึ่งถ้าผมอ่านจบแล้ว แน่นอนว่าได้มาเขียน Review ลงใน Blog แห่งนี้แน่นอนอันเป็นจุดประสงค์ที่ส่งเสริมกับเป้าหมายแรกเป็นอย่างดี และแน่นอนว่ามันไม่ได้หมดแค่ 4 เล่มนี้ ซึ่งเป็นเพียงขั้นต้นที่ อยากอ่านมานานแล้วว้อยย\nProgrammerต้องมี6Pack Season 2 ผมจำได้แม่นเลยว่าเมื่อ 2 ปีที่แล้วน้ำหนักเฉลี่ยของผมอยู่ที่ประมาณไม่เกิน 65 ซึ่งถ้าเทียบกับตอนนี้ถือว่า ผอมมาก\u0026hellip; ไม่ใช่สิ โคตรผอมเลย งั้นคงรู้แล้วสินะครับว่ามันเกิดอะไรขึ้น โครงการ Programmerต้องมี6Pack นี้จริงๆ แล้วผมไม่ได้เป็นคนคิดหรอกครับ ผมเอาแนวคิดมาจากพี่ @Juacompe ซึ่ง เป็นหนึ่งในโครงการที่ส่งเสริมสุขภาพ (ความหล่อ) ให้กับ Programmer โดยแท้ ถ้าอยากรู้รายละเอียดดูตามวิดีข้างล่างได้เลยครับ\nสำหรับเป้าหมายของผมเองนั้นอาจจะไม่ถึงขั้น 6 Pack สำหรับปีแรกแต่แน่นอนว่าต้องลดให้ได้ไม่ใช่แค่ให้ได้แต่เยอะด้วยวิธีการอยู่ในวิดีโอข้างต้นแล้วครับและถ้ามีโอกาสผมก็จะมาเขียนประสบการณ์ในโครงการนี้ลงที่นี่แน่นอน (นอกจากบ่นใน Facebook และ Twitter แล้ว)\nProject: User Acceptant Test Before New Year เป้าหมายสำคัญของ Project ที่ผมตั้งไว้แล้ว ตั้งแต่สอบ Project I เสร็จคือ ผมต้องทำ Product ตัวนี้ให้พร้อมสำหรับ User Acceptant Test ภายในปีใหม่ที่จะถึงนี้ครับ เวลา 3 เดือนสำหรับคนมีประสบการณ์ PHP Framework แบบผ่านๆ กับทีมอีก 2 คนที่เหลือที่ไม่ต่างกันนัก ต้องคอยดูว่าจะทำได้มั้ย ซึ่งถ้าทำไม่ได้มันจะส่งผลกระทบกับตารางชีวิตในเดือนมกราคมหลายอย่างเลยครับ\nวิธีการ ก่อนหน้าจะเขียนเอนทรี่นี้ผมเพิ่งอ่านเรื่อง 100 Days Goal ซึ่งเป็นแนวคิดที่ดีนการทำโครงการซักโครงการหนึ่งให้สำเร็จ รายละเอียดตอนนี้ยังพูดไม่ได้มาก ไว้มีโอกาสจะมาเล่าให้ฟังแน่นอน\nมีงานทำ อันนี้แน่นอนครับ ปีหน้าเวลานี้ ผมควรจะ \u0026ldquo;มีงานทำ\u0026rdquo; เป็นหลักเป็นแหล่งแล้ว บริษัทในใจก็มีอยู่ ความฝันในใจก็มี ตอนนี้สำหรับผมเหลือเพียงแต่ว่า ผมจะทำมันได้จริงหรือไม่ แค่นั้น\nมีเงินเก็บ 20k สำหรับใครที่มองว่าเงินเก็บ 20k น้อยนั้น ผมขออธิบายอย่างนี้ครับ คือ จริงๆ แล้วผมเป็นคนที่เก็บเงินไม่เก่งเลยในบางครั้งและเก่งโคตรในบางครั้ง มันเอาแน่เอานอนไม่ได้ เพราะฉะนั้นการกำหนดเป้าหมายซัก 20k ถือเป็นแค่จุดเริ่มต้นเท่านั้น บางทีผมอาจจะเก็บได้มากกว่านั้นก็ได้ใครจะไปรู้ ผมยังไม่รู้เลย\nหาเรื่องไป Silicon Valley ให้ได้ อันนี้แหละครับเป็นความฝันของจริง ตอนเรียนอาจจะทำไม่ได้เนื่องจาก ไม่มีรายได้ ไม่มีเงินทุนเป็นของตัวเอง แต่พอทำงานได้แล้ว ผมว่ามันก็ไม่ใช่เรื่องยากที่จะทำให้มันเป็นจริง เหตุผลที่อยากไป นอกจากจะไปสัมผัสโลกของ Developer ระดับโลกแล้ว ยังเป็นการไปหาโอกาสอีกทางหนึ่งอีกด้วย เป้าหมายนี้ไม่เกิน ตุลาคมปีหน้าครับ\nSpeaker at Barcamp Bangkhen#5 จริงๆ มันเป็นความตั้งใจของผมตั้งแต่ครั้งแรกที่ได้ไปงาน BCBK#1 แล้วแต่ผมพลาด BCBK ครั้งที่ 2 กับ 3 ไปและได้มีโอกาสมาอีกครั้งในครั้งที่ 4 และพบว่างานเปลี่ยนไปมาก อย่างไรก็ตาม ในเมื่อตั้งใจแล้ว ถ้ามันไม่หนักหนาเกินไปผมก็ตั้งใจจะทำให้มันจริง และยิ่งมีเรื่องที่อยากจะพูดอยู่ในใจแล้ว ผมว่าเป้าหมายอันนี้มีโอกาสประสบความสำเร็จได้ไม่ยากเลย\nProficient in CodeIgniter, Ruby on Rails, AngularJS, Vim, Git, Scrum เป้าหมายสุดท้าย ที่มันอยู่สุดท้าย เพราะผมคิดว่ามันทำได้ยากสุดครับ ฮ่าๆ อย่างไรก็ตาม ถ้าผมตั้งเป้าหมายไว้แล้ว ก็อยากจะทำให้ดีที่สุด จริงๆ แล้วเทคโนโลยีในอีก 1 ปีข้างหน้าอาจจะเปลี่ยนไป งานที่ผมทำอาจจะไม่มีโอกาสให้ผมได้ฝึกฝนในสิ่งเหล่านี้ แต่อย่างน้อยลองดูก็ไม่เสียหาย และดีกว่าถ้าเรามีเป้าหมายที่ชัดเจน\nหมดแล้วครับสำหรับปีนี้ อีก 1 ปีมาค่อยดูกันว่าผมจะทำได้จริงมั้ย ขอบคุณทุกคนที่มาอวยพรทั้งใน Facebook, Twitter, LINE, SMS หรือแม้กระทั้ง E-mail ขอบคุณทุกคนอีกครั้งครับ\nปล.ปีนี้ผมสนองความอยากของตัวเองด้วยการใช้เงินเก็บที่มีไปคว้า XBOX360 Wireless Controller มาใช้เป็นของตัวเอง ความสุขเล็กๆ น้อยๆ ที่ดีกว่า Controller ตัวละ 299.-ปล2.เรื่องฝึกงานว่าจะเขียนสั้นๆ เอาไปเอามายาวสุดเลย :)\nOriginal post at: https://yothinix.blogspot.com/2013/10/how-21-years-old-going-so-fast-and-what.html\n","permalink":"https://yothinix-com.pages.dev/how-21-years-old-going-so-fast-and-what-then/","summary":"\u003cp\u003eวันที่ 9 ที่ผ่านมาวันคล้ายวันเกิดผมเองครับ แต่ละปีผ่านไปเราถูกบอกว่าเราแก่ขึ้นแล้วนะ ภาระความรับผิดชอบเยอะขึ้นแล้วนะ นั่นคือสิ่งที่เราดำเนินไปและกำลังดำเนินต่อไปทุกวินาทีที่เราใช้ชีวิตอยู่ สิ่งหนึ่งที่ผมเรียนรู้เกี่ยวกับ Agile มาคือ การมองย้อนกลับไปหรือที่ชุมชนชาว Agile เรียกกันว่า Retrospective ไม่ใช่เรื่องเสียเวลาเลย ไม่ใช่การมองอดีตจะเป็นการเสียเวลาอย่างเดียว แต่เป็นการทำให้เรารู้ว่าเราเคยทำอะไรดีๆ มาบ้าง, เคยผิดพลาดตรงไหน และเราจะปรับปรุงมันได้อย่างไร ฟังดูคุ้นๆ ใช่มั้ยครับ Good, Bad, Try นั่นเอง แต่เราจะพูดถึงสิ่งนี้ทีหลัง\u003c/p\u003e\n\u003cp\u003eปีที่ผ่านมานับตั้งแต่เดือนตุลาคมปีที่แล้ว ถ้านับเป็นเวอร์ชั่นของ Software คงเรียกได้ว่าเป็น Major Change เลยทีเดียว ลองไล่ดูว่าเกิดอะไรขึ้นบ้าง\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/how-21-years-old-going-so-fast-and-what-then/DAN_4997_hu_a84455d33e84da64.webp\"\n       srcset=\"/how-21-years-old-going-so-fast-and-what-then/DAN_4997_hu_a84455d33e84da64.webp 480w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"480\" height=\"318\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\u003c/p\u003e\n\u003ch2 id=\"foreign-student-internship-program-2013--us-embassy-bangkok\"\u003eForeign Student Internship Program 2013 @ U.S. Embassy Bangkok\u003c/h2\u003e\n\u003cp\u003eเรื่องนี้นับว่าเป็นเรื่องใหญ่ที่สุด จริงๆ แล้วผมตั้งใจจะเขียนเรื่องฝึกงานเต็มๆ ซักตอนนึงเลย แต่ไม่มีโอกาสซักที ตอนนี้เลยเอาแบบย่อๆ ไปก่อน คือ ช่วงประมาณปลายเดือนกันยายน ของปีที่แล้ว เป็นเรื่องธรรมดาของนักศึกษาปี 3 ทีต้องเริ่มหาที่ฝึกงานแล้ว ซึ่งจริงๆ ในตอนนั้นผมก็เล็งไว้หลายที่มาก แต่จนแล้วจนรอดก็ยังไม่ได้สมัครที่ไหน โครงการ FNSIP2013 ผมรู้จักจากคนใกล้ตัวนี้เอง ซึ่งบอกตามตรงว่าไม่เคยคิดว่าจะมีโปรแกรมแบบนี้อยู่ในโลก อาจจะเป็นเพราะการที่เราเรียนในสายวิศวกรรมศาสตร์ ทำให้ไม่ค่อยสนใจ การฝึกงานในองค์กรอะไรแบบนี้นัก เพราะส่วนใหญ่มักมุ่งไปแต่เอกชนอย่างเดียว\u003c/p\u003e","title":"HOW 21 YEARS OLD GOING SO FAST, AND WHAT THEN…"},{"content":"ช่วงเวลาสองสัปดาห์ที่ผ่านมาหลังสอบไล่ Project I เสร็จหลาย คนอาจจะเริ่มอ่านหนังสือสอบไล่ตัวอื่นกันบ้างแล้ว ผมก็สอบครับ แต่สอบน้อยกว่าคนอื่น (3 ตัว) ช่วงเวลาที่หยุดระหว่างสอบ นอกจากจะอ่านหนังสือ แล้วสิ่งที่ผมไม่อาจลืมได้คือ Project II เหลือเวลาให้ Implement กับ Testing เพียงแค่ 4 เดือนโดยประมาณนับจากนี้ ซึ่งสิ่งที่ยากไม่ใช่เวลา แต่เป็นคนครับ ผมตั้งคำถามกับตัวเองว่าทำยังไงถึงจะให้คน 3 คนทำงานใน Project เดียวกันได้ เร็วที่สุด\nจุดประสงค์ที่ผมเขียนเอนทรี่ในชุด Team Development Environment \u0026amp; Workflow (ตอนต่อๆ ไปจะเรียกมันว่า TDE\u0026amp;W นะครับ) ก็เพื่อที่จะรวบรวมคำถามและวิธีการที่ผมเคยสงสัยมาตลอดในการสร้าง Software ออกมาตัวนึง เพื่อเก็บไว้ใช้อ่านทวนทีหลัง และที่สำคัญไว้เผยแพร่ความรู้ให้กับคนที่ยังไม่รู้เหมือนผมก่อนหน้านี้ จริงอยู่ถ้าในโลกการทำงานแล้วเรื่องแบบนี้บางครั้งเป็นเรื่องที่ Basic มากแต่ถ้ามองย้อนกลับมาในระดับการศึกษาผมค้นพบว่า น้อยคนที่จะเรียนรู้ลำดับการทำงานแบบนี้ซึ่งสามารถช่วยให้ทำงานได้อย่างเป็นระบบและมีประสิทธิภาพสูงขึ้นมาก\nGit Workflow คำถามแรกที่ผมถามตัวเองอย่างที่ผมได้บอกไปแล้วผมคิดถึง Git ก่อนเลยครับเนื่องจากมีประสบการณ์การทำงานกับมันมาบ้างใน Project ที่ใช้ Rails แต่สิ่งสำคัญอย่างนึงที่ผมยังไม่รู้คือ Git Workflow ครับโชคดีที่มีคนเขียนแนะนำเรื่องนี้ไว้แล้วในบทความเรื่องA Successful Git branching model\nsrc: https://nvie.com/posts/a-successful-git-branching-model/\nบทความนี้อธิบายไว้อย่างคร่าวๆว่าในการ Develop Software ขึ้นมาซักตัวนั้นเราควรจะมีแผนการในการแตกสาขา (Branch) ของ Source Code ที่เราเก็บไว้อย่างไรโดยจะแตกออกเป็น Branch หลักๆอยู่ 2 Branch คือ\nMaster :: เป็น Branch หลักของตัวโค้ดเวอร์ชั่นสมบูรณ์แล้วพร้อมจะนำเข้าสู่ Server ในระดับ Production ซึ่งถ้ามองตามการเปลี่ยนแปลงภายในระบบก็คือ Major Change นั้นเองครับ Develop :: เป็น Branch หลักในการทำงานของทีม โดย Branch นี้จะมีการแก้ไขเปลี่ยนแปลงอยู่เกือบตลอด และเมื่อโค้ดใน Branch นี้สมบูรณ์แล้วก็จะถูก Merge เข้าสู่ Master Branch ต่อไป นอกจากนั้นแล้วยังมี Branch อื่นๆ ที่มีความจำเป็นในการทำงานเนื่องจาก ถ้ามีแค่ 2 Branch นี้แล้ว Developer ทำการยำการทำงานอยู่ที่ Develop Branch อย่างเดียวก็ยังมีโอกาสสูงมากที่โปรเจ็คจะ Fail เนื่องจากโค้ดมันชนกัน ด้วยเหตุนี้จึงมี Branch อื่นๆ ที่เรียกว่า Supporting branch ไว้สำหรับการทำงานในส่วนต่างๆ ที่แยกจากกันดังนี้\nFeature :: สำหรับใน branch นี้มีไว้เพื่อให้นักพัฒนาทำการแยกไป เพื่อพัฒนา Function/Module หรือความสามารถของระบบเดี่ยวๆ แยกต่างหาก เพื่อป้องกันความผิดพลาด เมื่อพัฒนาเสร็จเรียบร้อยดีแล้ว ก็จะรวม branch นี้กลับมาที่ develop branch เพื่อจะรอปล่อยใน Minor release ต่อไป Release :: จะเป็นตัวเชื่อมระหว่าง Develop กับ Master เมื่อทีมประเมินว่าโค้ดที่อยู่ใน develop branch นั้นเสถียรดีแล้ว ก็จะทำการปล่อย Minor release ที่ branch นี้เพื่อเช็คความเรียบร้อยอีกครั้งนึง ซึ่งถ้ายังมีปัญหาอยู่ใน branch นี้ก็จะทำการรวมกลับไปที่ develop branch เพื่อทำการแก้ไขข้อผิดพลาด (Bugfixes) ก่อนจะทำการส่งกลับมาที่ Release branch ใหม่ เมื่อ Team เห็นว่าโค้ดไม่มีข้อผิดพลาดอะไรแล้วก็จะทำการรวมไปที่ Master branch เพื่อส่งเป็น Major Update ต่อไป Hotfixes :: เมื่อโค้ดที่อยู่ใน Master branch มีปัญหาทางทีมจะทำการแก้ปัญหาในจุดนั้นทันทีโดยแยกโค้ดออกมาที่ branch นี้ เมื่อทำการแก้ไขข้อผิดพลาดเสร็จเรียบร้อยแล้ว ทางทีมก็จะทำการรวมโค้ดกลับไปที่ Master branch เพื่อแก้ไขข้อผิดพลาดและ Develop branch เพื่อทำการพัฒนาต่อไป การติดตั้ง Git ก่อนที่เราจะทำการใช้งาน Git เป็น Version Control Software ของโปรเจ็คเราได้นั้นเราต้องมี Software ของมันก่อนครับซึ่งสามารถเข้าไปโหลดเวอร์ชั่นล่าสุดได้ที่http://git-scm.com/ครับซึ่งระหว่างการติดตั้งจะมีให้เราเลือกว่าให้เราใช้ Git ผ่านทางไหนได้บ้างแนะนำให้เลือก Run Git from the Windows Command Prompt ครับ (เดี๋ยวจะได้ใช้ประโยชน์ในอนาคต) เมื่อติดตั้งเสร็จแล้วก็จะสามารถลองใช้งานได้ผ่านทาง Git Bash หน้าตาประมาณรูปข้างบนครับหรือจะใช้ Git GUI ก็ได้แต่เราจะยังไม่ทำการตั้งค่าเบื้องต้น Git ตอนนี้ครับเพราะจะใช้ตัวนี้เป็นแค่ Back-end ของ Client อีกตัวที่เราจะใช้กันจริงๆซึ่งก็คือ SourceTree ครับ\nการสมัครสมาชิก GitHub สำหรับ Host หรือ Repository ของโค้ดในตอนนี้ผมเลือกใช้ GitHub ก่อนนะครับ (ตอนหลังๆจะย้ายไปใช้ตัวอื่น) โดยการสมัครสมาชิกสามารถเข้าไปสมัครได้ที่หน้าแรกตาม URL นี้เลยครับhttps://github.com/เมื่อสมัครสมาชิกเข้ามาแล้วส่วนสำคัญคือการตั้งค่า SSH Keys ที่จะใช้ในการยืนยันตัวตนของเครื่องเราเวลาที่จะทำการส่งโค้ดเข้าสู่ Repository ของตัว GitHub โดยสามารถเข้าไปตั้งค่าได้ที่ Account settings \u0026gt; SSH Keys โดยจะมีลิงค์บอกวิธีการสร้าง Keys อยู่ข้างบนสำหรับใน Windows ให้เปิด Git Bash ขึ้นมาแล้วทำตามขั้นตอนดังนี้ครับ\nเช็คดูก่อนว่าในเครื่องเราได้มีการสร้าง ssh keys ไว้แล้วหรือยังโดยพิมพ์คำสั่ง $ cd ~/.ssh ซึ่งถ้าขึ้นว่า No such file or directory ก็แสดงว่าเครื่องเรายังไม่เคยสร้าง Keys ใดๆ ไว้นะครับ ให้ทำการสร้าง SSH Key ใหม่ขึ้นมาโดยพิมพ์คำสั่ง\n$ ssh-keygen -t rsa -C \u0026ldquo;your_email@example.com\u0026rdquo;\nโดย email ที่ใส่ก็คือ email เดียวกับที่เราใช้สมัคร Account ของ GitHub ไปก่อนหน้านี้ครับระหว่างนั้นจะมีให้เราใส่ passphrase เพื่อเพิ่มความปลอดภัยของ Key ที่เราสร้างขึ้นครับซึ่งถ้าไม่ต้องการเปลี่ยนแปลงอะไรก็กดปุ่ม Enter ข้ามไปครับ เมื่อสร้างคีย์เสร็จเรียบร้อยแล้วนะครับให้เราทำการ Copy ตัวเนื้อ Key โดยพิมพ์คำสั่ง\n$ clip \u0026lt; ~/.ssh/id_rsa.pub\nหลังจากนั้นแล้วให้เรากลับมาที่หน้า Account settings \u0026gt; SSH Keys แล้วเลือก Add SSH Key แล้วทำการ Paste ตัวเนื้อ Key ลงในช่อง Key เสร็จเรียบร้อยแล้วก็กด Add key ก็เป็นอันเสร็จเรียบร้อยครับ (ถ้ามีขึ้นให้ยืนยันพาสเวิร์ดอีกทีก็กรอกแล้วกด Enter ไปตามขั้นตอนครับ) ตอนนี้เราก็ได้ Add Public Key ของเราเข้าที่ GitHub แล้วนะครับ โดยเราสามารถทดสอบดูได้ว่า Key ที่เราแอดไปสามารถใช้ได้หรือไม่โดยลองพิมพ์คำสั่งนี้ลงใน Git Bash ครับ\n$ ssh -T git@github.com\nหลังจากนั้นแล้วจะมีถามยืนยันที่จะเพิ่ม Host ก็พิมพ์ \u0026ldquo;yes\u0026rdquo; แล้วรอซักพัก ถ้าขึ้นว่า\nHi username! You\u0026rsquo;ve successfully authenticated, but GitHub does not provide shell access. ก็แสดงว่า Key ที่เราเพิ่มเข้าไปตะกี้สามารถใช้งานได้แล้วนะครับ การติดตั้ง SourceTree เพื่อความสะดวกนะครับผมได้เลือกใช้ SourceTree ซึ่งเป็น Git GUI Client ตัวนึงในการใช้งานเนื่องจากไม่ต้องเสียเวลาจำคำสั่งมากและใช้งานง่ายสำหรับมือใหม่ในการทำความเข้าใจ Git รวมถึงสนับสนุนการทำงานแบบ Git Flow ที่ได้กล่าวไปแล้วข้างต้นได้อย่างเต็มที่ตัวโปรแกรมสามารถเข้าไป Download ตัวติดตั้งได้ตาม URL นี้ครับhttp://www.sourcetreeapp.com/\nเมื่อติดตั้งเสร็จแล้วจะมีตัวเลือกให้เราตั้งค่าพื้นฐานของการใช้งานก็ใส่ Full Name และ Email address ไปนะครับ (อย่าลืมกด I agree to the SourceTree license agreementนะครับ) หลังจากนั้นกด Next ครับในส่วนของ SSH Client Configuration ก็ให้เลือกเป็น OpenSSH ต่อมาจะเป็นการตั้งค่ากับ remote repository ก็ใส่ Username กับ Password ของ github ไปให้เรียบร้อยแล้วกด Finish ระบบจะทำการทดสอบการเชื่อมต่อถ้าเชื่อมต่อได้ก็จะเข้าสู่โปรแกรมได้เลยครับสำหรับในตอนแรกก็จบเพียงเท่านี้นะครับในตอนต่อไปเราจะมาพูดถึงการใช้งาน Git เบื้องต้นโดยใช้ SourceTree กันครับ\nOriginal post at: https://yothinix.blogspot.com/2013/10/team-development-environment-workflow-1.html\n","permalink":"https://yothinix-com.pages.dev/team-development-environment-workflow-1-version-control-system/","summary":"\u003cp\u003eช่วงเวลาสองสัปดาห์ที่ผ่านมาหลังสอบไล่ Project I เสร็จหลาย คนอาจจะเริ่มอ่านหนังสือสอบไล่ตัวอื่นกันบ้างแล้ว ผมก็สอบครับ แต่สอบน้อยกว่าคนอื่น (3 ตัว) ช่วงเวลาที่หยุดระหว่างสอบ นอกจากจะอ่านหนังสือ แล้วสิ่งที่ผมไม่อาจลืมได้คือ Project II เหลือเวลาให้ Implement กับ Testing เพียงแค่ 4 เดือนโดยประมาณนับจากนี้ ซึ่งสิ่งที่ยากไม่ใช่เวลา แต่เป็นคนครับ ผมตั้งคำถามกับตัวเองว่าทำยังไงถึงจะให้คน 3 คนทำงานใน Project เดียวกันได้ เร็วที่สุด\u003c/p\u003e\n\u003cp\u003eจุดประสงค์ที่ผมเขียนเอนทรี่ในชุด \u003cem\u003eTeam Development Environment \u0026amp; Workflow\u003c/em\u003e (ตอนต่อๆ ไปจะเรียกมันว่า TDE\u0026amp;W นะครับ) ก็เพื่อที่จะรวบรวมคำถามและวิธีการที่ผมเคยสงสัยมาตลอดในการสร้าง Software ออกมาตัวนึง เพื่อเก็บไว้ใช้อ่านทวนทีหลัง และที่สำคัญไว้เผยแพร่ความรู้ให้กับคนที่ยังไม่รู้เหมือนผมก่อนหน้านี้ จริงอยู่ถ้าในโลกการทำงานแล้วเรื่องแบบนี้บางครั้งเป็นเรื่องที่ Basic มากแต่ถ้ามองย้อนกลับมาในระดับการศึกษาผมค้นพบว่า น้อยคนที่จะเรียนรู้ลำดับการทำงานแบบนี้ซึ่งสามารถช่วยให้ทำงานได้อย่างเป็นระบบและมีประสิทธิภาพสูงขึ้นมาก\u003c/p\u003e\n\u003ch1 id=\"git-workflow\"\u003eGit Workflow\u003c/h1\u003e\n\u003cp\u003eคำถามแรกที่ผมถามตัวเองอย่างที่ผมได้บอกไปแล้วผมคิดถึง Git ก่อนเลยครับเนื่องจากมีประสบการณ์การทำงานกับมันมาบ้างใน Project ที่ใช้ Rails แต่สิ่งสำคัญอย่างนึงที่ผมยังไม่รู้คือ Git Workflow ครับโชคดีที่มีคนเขียนแนะนำเรื่องนี้ไว้แล้วในบทความเรื่อง\u003ca href=\"http://nvie.com/posts/a-successful-git-branching-model/\"\u003eA Successful Git branching model\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"/team-development-environment-workflow-1-version-control-system/git-model-2x_hu_fa9d29d0d48f6493.webp\"\n       srcset=\"/team-development-environment-workflow-1-version-control-system/git-model-2x_hu_26225a7f09978c2e.webp 480w, /team-development-environment-workflow-1-version-control-system/git-model-2x_hu_fa9d29d0d48f6493.webp 960w\"\n       sizes=\"(max-width: 960px) 100vw, 960px\"\n       width=\"960\" height=\"1272\"\n       alt=\"\"\n       loading=\"lazy\" decoding=\"async\"\u003e\n\u003cem\u003esrc: \u003ca href=\"https://nvie.com/posts/a-successful-git-branching-model/\"\u003ehttps://nvie.com/posts/a-successful-git-branching-model/\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e","title":"TEAM DEVELOPMENT ENVIRONMENT \u0026 WORKFLOW (1) - VERSION CONTROL SYSTEM"},{"content":"ขณะกำลังทำ Sprint Planning ไหนๆ วันนี้ก็ได้ Applied Scrum เข้ากับ Project อย่างเต็มตัววันแรกละ ขอเขียนอะไรไว้เป็นที่ระลึกหน่อย\nจริงๆ ผมตั้งใจไว้ว่าจะสอนทีม Senior Project ทำ Agile Methodology มาซักพักแล้ว ไอเดียนี้มันติดใจมาตั้งแต่ครั้งไปร่วมงาน Agile Thailand 2013 แต่ติดปัญหาอยู่สองสามข้อ อย่างแรกคือ ผมยังมีความรู้พื้นฐานเรื่อง Agile ไม่มากพอ อย่างที่สอง ผมยังมองภาพรวมของ Project ตัวเองไม่ออก อย่างที่สามสำคัญสุดขี้เกียจ\nเวลาผ่านไปเดือนกว่าๆ ถ้าไม่นับเรื่องเชียร์ เร่งส่ง Proposal และก็หาข้อมูลเกี่ยวกับ Data Mining ถ้าผมว่าง ผมก็จะพยายามหาความรู้เพิ่มเติมเกี่ยวกับ Agile มาโดยตลอด แรกๆ ก็หา Tools บ้างแต่ยังไม่ครบเพราะได้ Tools มาก็ใช้ไม่เป็น แถมมีคนแขวะ ไว้อีกว่า Collaboration more than tool เพราะฉะนั้นจะไปสนทำไม (แต่ก็ยังสนอยู่) จนกระทั่งผมค้นพบหนังสือ The Agile Samurai ซึ่งผมคิดว่าเป็นหนังสือที่อ่านง่าย อ่านสบาย เกี่ยวกับ Agile เล่มนึง แต่ผมอ่านจบไปแค่ Part II เพราะเจียดเวลามาอ่านไม่ได้จริงๆ เนื้อหา Data Mining บีบ ทำให้ผมต้องรีบหาวิธีทำ Agile แล้วมาประยุกต์ใช้กับทีมให้เร็วที่สุด ก่อนที่ทีมจะทำงานไปมากกว่านี้\nผมรู้จัก Scrum มาจริงๆ ก็เกือบปีแล้ว ตั้งแต่น้อง Xenon เอามาแนะนำให้รู้จักที่ CSAG ใช้เป็นวิธีการประชุม แต่เนื่องด้วยตอนนั้นผมยังไม่สนใจ Software Development จริงๆ จังๆ เลยไม่สนใจเท่าไร ผมมาสะดุดอีกทีก็หลังจากงาน ATH2013 มีคนแชร์ภาพ Scrum Process เป็นภาพการ์ตูนญี่ปุ่นโมเอะ ดังภาพข้างล่าง ซึ่งสะดุดตาเป็นอย่างมาก จนกระทั่งมาถึงเมื่ออาทิตย์ก่อน ผมพอมีเวลาว่างหาข้อมูลเกี่ยวกับ Agile อีกก็ไปสะดุดเข้าที่เว็บ http://scrumprimer.org/ ซึ่งเป็นคู่มือการทำ Scrum เบื้องต้น แบบสั้นๆ ซึ่งระหว่างค้นหาข้อมูลผมก็ค้นพบอีกว่ามีพี่ๆ ในกลุ่ม Agile66 เคยมีโครงการแปลหนังสือเล่มนี้เป็นภาษาไทยด้วย ค้นไปจนเจอจนได้ต้นฉบับมาแล้วผมก็อ่านครับ ภายใน 30 หน้าผมตรัสรู้ อย่างน้อย ปัจจัยข้อแรกเรื่องที่ผมไม่มีความรู้พื้นฐานก็หายไปละ ผมพร้อมละที่จะประยุกต์ใช้ Scrum ในทีมผม มันต้องออกมาดูดีแน่ และผมก็ไม่ต้องใช้ Waterfall ที่โคตรหน้าเบื่อเหมือนกลุ่มอื่นซักที เย้ คิดแค่นี้ก็ตัวลอยละครับ\nhttp://scrumprimer.org/anime ผมเตรียมตัวอ่านอยู่สองสามรอบ จนเข้าใจระดับหนึ่ง หนังสือ Scrum Primer เหมาะสำหรับทีมที่ทำ Scrum ใหม่ๆ มากครับ เพราะเตรียมเนื้อหาไว้ให้พอเพียง ผมเข้าใจว่าทีมผมยังใหม่กับ Agile มาก เพราะอย่างน้อยวิชา SE ก็ไม่ได้เน้นในจุดนี้ มากนัก ก็คือต้องเริ่มใหม่เกือบหมด แต่ยังไม่เป็นไร วิธีที่ผมถ่ายทอดให้เพื่อนจะคล้ายๆ กับเวลาเรียนวิชาอะไรวิชาหนึ่งแล้วมาสรุปให้เพื่อนฟัง (จริงๆ ผมก็สรุปเป็น Bullet เก็บไว้เองแล้วชุดหนึ่ง) แล้วมาถ่ายทอดให้ฟัง ไล่ไปทีละจุดตามเนื้อหาใน Scrumprimer ประกอบกับภาพ Overview ใช้ได้ผลดี จนทีมมีความรู้ ความเข้าใจ Scrum ตั้งแต่ Role ของแต่ละคน Product Backlog, Sprint Planning, Sprint Backlog, Daily Scrum, Burndown Chart, Product Backlog Refinement อาจจะไม่เข้าใจ 100% แต่อย่างน้อยก็พอจะเข้าใจ Concept ได้ว่าคืออะไร ไว้พอจะประยุกต์ใช้และถ่ายทอดต่อไปได้ แค่นี้ผมก็ดีใจแล้วครับ (ที่หนีพ้น Waterfall ได้มากขึ้นก้าวหนึ่ง)\nOriginal post at: https://yothinix.blogspot.com/2013/07/scrum-1st-day-introduction-to-scrum.html\n","permalink":"https://yothinix-com.pages.dev/scrum-1st-day-introduction-to-scrum-with-my-team/","summary":"\u003ctable align=\"center\" cellpadding=\"0\" cellspacing=\"0\" class=\"tr-caption-container\" style=\"border-collapse: collapse; border-spacing: 0px; color: rgb(0, 0, 0); font-family: Lora, serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; margin-left: auto; margin-right: auto; text-align: center;\"\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd style=\"padding: 0px; text-align: center;\"\u003e\u003ca href=\"https://4.bp.blogspot.com/-nrnbK1LuPt4/UdxrhS28FTI/AAAAAAAAAqs/s4WWYwYPi_Q/s1600/a1d98458e8b211e2b83422000a1f9e4c_7.jpg\" imageanchor=\"1\" style=\"background: transparent; color: rgb(55, 174, 190); text-decoration: none; display: inline-block; margin-left: auto; margin-right: auto;\"\u003e\u003cimg border=\"0\" height=\"320\" src=\"https://4.bp.blogspot.com/-nrnbK1LuPt4/UdxrhS28FTI/AAAAAAAAAqs/s4WWYwYPi_Q/s320/a1d98458e8b211e2b83422000a1f9e4c_7.jpg\" width=\"320\" style=\"border: 0px; max-width: 100%; height: auto;\"\u003e\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd class=\"tr-caption\" style=\"padding: 0px; color: rgb(0, 0, 0); font: 400 12px / 1.7 Montserrat, sans-serif; text-align: center;\"\u003eขณะกำลังทำ Sprint Planning\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\n\u003cp\u003eไหนๆ วันนี้ก็ได้ Applied Scrum เข้ากับ Project อย่างเต็มตัววันแรกละ ขอเขียนอะไรไว้เป็นที่ระลึกหน่อย\u003cbr\u003e\n\u003cbr\u003e\nจริงๆ ผมตั้งใจไว้ว่าจะสอนทีม Senior Project ทำ Agile Methodology มาซักพักแล้ว ไอเดียนี้มันติดใจมาตั้งแต่ครั้งไปร่วมงาน Agile Thailand 2013 แต่ติดปัญหาอยู่สองสามข้อ อย่างแรกคือ ผมยังมีความรู้พื้นฐานเรื่อง Agile ไม่มากพอ อย่างที่สอง ผมยังมองภาพรวมของ Project ตัวเองไม่ออก อย่างที่สามสำคัญสุดขี้เกียจ\u003cbr\u003e\n\u003cbr\u003e\nเวลาผ่านไปเดือนกว่าๆ ถ้าไม่นับเรื่องเชียร์ เร่งส่ง Proposal และก็หาข้อมูลเกี่ยวกับ Data Mining ถ้าผมว่าง ผมก็จะพยายามหาความรู้เพิ่มเติมเกี่ยวกับ Agile มาโดยตลอด แรกๆ ก็หา Tools บ้างแต่ยังไม่ครบเพราะได้ Tools มาก็ใช้ไม่เป็น แถมมีคนแขวะ ไว้อีกว่า Collaboration more than tool เพราะฉะนั้นจะไปสนทำไม (แต่ก็ยังสนอยู่) จนกระทั่งผมค้นพบหนังสือ The Agile Samurai ซึ่งผมคิดว่าเป็นหนังสือที่อ่านง่าย อ่านสบาย เกี่ยวกับ Agile เล่มนึง แต่ผมอ่านจบไปแค่ Part II เพราะเจียดเวลามาอ่านไม่ได้จริงๆ เนื้อหา Data Mining บีบ ทำให้ผมต้องรีบหาวิธีทำ Agile แล้วมาประยุกต์ใช้กับทีมให้เร็วที่สุด ก่อนที่ทีมจะทำงานไปมากกว่านี้\u003c/p\u003e","title":"SCRUM 1ST DAY - INTRODUCTION TO SCRUM WITH MY TEAM"}]