👶 Algorithm

🤨 โครงสร้างข้อมูลเรียนไปทำไม? โตไปไม่ได้ใช้ ?

😢 ปัญหา

หลายคนที่เรียน Computer Science หรือ Computer Engineering มาก็คงจะหนีไม่พ้นที่จะถูกบังคับให้เรียน Data Structure & Algorithm มาชิมิ แล้วพอมาอยู่ในโลกของการเขียนซอฟต์แวร์จริงๆก็อาจจะมีคำถามว่า ไอ้วิชาบร้านี้เรียนมาทำไมฟระ เสียเวลาชีวิตจุง 🤬

ดังนั้นบทความนี้แมวน้ำจะมาแฉให้ฟังว่า วิชานี้คือตัวที่เอาไว้แบ่งระหว่าง คนที่เขียนโค้ดได้ กับ คนที่ออกแบบ Software Architecture ได้ หรือพูดแบบบ้านๆก็คือ แค่โบกปูนเป็นหรือคนที่สร้างตึกระฟ้าได้นั่นเอง

ฟหกดเอกอาสว!@#$%^&* 😎 โครงสร้างซอฟต์แวร์จะเทพหรือกากมันคือเรื่องนี้เบย

❓ Data Structure & Algorithm คือไย ?

ขอเกริ่นให้คนที่ไม่ได้เรียนวิชานี้ หรือลืมไปแบ้วนิสนุง (ใครจำได้ก็ข้ามไปดูด้านล่างโลด)

Algorithm

เวลาที่เราเจอปัญหาอะไรก็ตาม เช่น อยากให้โปรแกรมทำนั่นนู่นนี่ได้ สิ่งที่เราจะต้องทำก็คือ หาวิธีการแก้ไขปัญหา หรือนั่นก็คือ Algorithm นั่นเอง ซึ่งขั้นตอนนี้เราจะคิดออกมาเป็นขั้นตอน 1 2 3 4 โดยไม่ยึดติดว่ามันเป็นภาษาอะไรนั่นเอง ซึ่งปัญหาที่เราเจออาจจะมีวิธีการแก้ปัญหาหลายๆแบบก็ได้ (มี Algorithm มากกว่า 1 ตัว)

สรุปสั้นๆ Algorithms คือการ Define steps ที่ใช้ในการแก้ปัญหา

Data Structure

หลังจากที่เรารู้แล้วว่าเราจะแก้ปัญหานั้นยังไง เราก็จะเลือกวิธีการแก้ปัญหาที่เราคิดว่าดีที่สุดมา แล้วเราก็จะเอามันไปออกแบบว่า ถ้าจะเขียนโค้ดเพื่อให้มันทำงานตาม Algorithm นั้นๆได้ เราจะออกแบบ class ต่างๆ module ต่างๆยังไง เพื่อให้มันทำงานตาม algorithm นันๆได้นั่นเอง และแน่นอนว่า 1 Algorithm ก็สามารถมี Data Structure ได้มากกว่า 1 แบบเช่นกัน

สรุปสั้นๆ Data Structure คือการ Define structure ที่ใช้ในการเขียนโค้ดให้ได้ตาม Algorithm นั้นๆ

จากที่มโนมาทั้งหมดเราก็จะเห็นว่า Algorithm กับ Data Structure เป็นของที่ เกิดมาคู่กัน โดยมันมีเป้าหมายหลักอันเดียวกันคือ แก้ไขปัญหาที่เรากำลังเจออยู่นั่นเอง ซึ่งแต่ละ Algorithm แต่ละ Data Structure ก็จะมีข้อดี ข้อเสียที่แตกต่างกันไป

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

😅 มันจำเป็นต้องรู้ด้วยเหรอ?

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

🤔 พูดให้เห็นภาพหน่อยได้ไหม?

จัดไป! ... สมมุติว่าเราต้องเขียนเว็บง่ายๆ 1 ตัว แล้วให้มันมี ระบบนับยอดคนดู เราจะทำยังไง?

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

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

อะเช พอมาถึงจุดนี้ความสำคัญของ Algorithm & Data Structure มันจะเริ่มแผลงฤทธิ์ให้เราเห็นความสำคัญของมันมากขึ้นคือ โครงสร้างที่เป็น Centralized system แบบในรูปด้านบน มันจะมีคอขวดที่จะทำให้ระบบล่มได้ง่ายๆ เช่น สมมุติว่าตัว Database ที่เลือกใช้มีความสามารถรับการเขียนได้ 100 ครั้ง/วินาที แล้วจะเกิดอะไรขึ้นถ้ามีคนเข้าเว็บเกิน 100 คน/วินาทีกันล่ะ? . . . เมื่อหัวใจมันล่มระบบก็ตายนั่นเอง

Single point of failure จุดอ่อนของระบบที่เป็น Centralized System คือ ถ้าตัวกลางตาย ทั้งระบบก็จะมีปัญหา ซึ่งการแก้ปัญหาแบบกากสุดก็คือ เพิ่มตัวกลางหลายๆตัว ซึ่งมันก็จะมีปัญหาในอีกรูปแบบตามมา เช่นการทำ synchronization บลาๆ

จากที่ว่ามานี่คือตัว ขีดจำกัดของ Architecture ประเภทนี้ ดังนั้นถ้าเราอยากที่จะแก้ปัญหาที่เป็น Centralized System เราก็จะต้องเลือก Algorithm & Data Structure ที่เหมาะกับ Architecture ของมันนั่นเอง

😒 Algorithm มันเกี่ยวไร ?

จากปัญหาตัวนับคนที่ว่ามา ถ้าเราเลือก Algorithm ที่ต่างกัน ผลลัพท์กับ Architecture ก็จะไปกันคนละโลกเลย เช่น เรายอมให้ตัวเลขคนเข้าเว็บมันคลาดเคลื่อนได้นะ แต่ถ้าปล่อยไว้ซักพักเดี๋ยวมันจะถูกเอง ซึ่งเราเรียกของแบบนี้ว่า Eventual consistency นั่นเอง

Eventual consistency เป็นหลักที่ยอมให้ไม่สอดคล้องกันได้ แต่สุดท้ายจะสอดคล้องกันเอง พูดแล้วอาจจะ งงๆ แต่ที่เราเคยเจอแน่ๆคือ ยอดคนดูวีดีโอของ Youtube ยังไงล่ะ มันไม่ใช่ยอดที่อัพตลอดเวลา ซึ่งวีดีโอเดียวกันอาจจะเห็นยอดคนดูต่างกันก็ได้ ซึ่งปล่อยทิ้งไว้ซักพัก เดี๋ยวเลขนั้นมันก็จะเป็นยอดคนดูที่ถูกต้องเอง ซึ่งแนวคิดนี้มาจากการทำ Distrubuted System ยังงุยล่ะ

จากที่ว่ามาเมื่อเราเลือก Algorithm ที่เป็น Eventual consistency แล้ว เราก็ต้องมี Data Structure ที่เหมาะกับกับ Architecture ในลักษณะนั้นด้วยมันถึงจะทำงานร่วมกันได้ ตามรูปเลย

เข้าใจหลักพื้นฐานนี้คได้ก็เริ่มอ่าน Blockchain ต่อได้เลยนะ หุหุ

อธิบายรูปนิสนุง เซิฟเวอร์แต่ละตัวทำการนับยอดของใครของมัน ซึ่งเมื่อยอดตัวมันเองเปลี่ยน มันก็จะแจ้งไปบอกเพื่อนๆของมันด้วยเสมอ ทำให้แต่ละเซิฟเวอร์ทำงานแยกออกจากกันได้ ไม่เกิด Single point of failure ขึ้น

เหมือนเรื่องราวจะจบแล้ว แต่ยัง!! เพราะอย่างที่เคยบอกไปว่าทุก Algorithm ทุก Architecture ย่อมมีข้อดี และ ข้อเสีย หรือ ขีดจำกัดทางสายเลือดของมันเสมอ ซึ่งจากรูปด้านบน การทำงานของเซิฟเวอร์แต่ละตัวจะต้องส่งผ่าน network / internet ดังนั้นมันก็จะมีปัญหาเรื่อง ส่งถึงบ้างไม่ถึงบ้าง, ข้อมูลที่ส่งไปก่อนถาจจะถึงช้ากว่าตัวที่ส่งไปทีหลัง, Concurrency บลาๆ ซึ่งทั้งหมดทั้งมวลมันจะก่อให้เกิดสิ่งที่เรียกว่า ความขัดแย้ง (Conflict) ได้ เช่น เซิฟเวอร์ A บอกว่ายอดรวมตอนนี้เป็น 3 แสนคนนะ แต่ B บอกว่าไม่ใช่ 5 แสนต่างหาก ส่วน C บอกว่า 9 ล้านคนเฟร้ย และ D บอกว่าของตรูพึ่งนับได้ 1 พันคนเอง ... แล้วเราจะแก้ปัญหาความขัดแย้งนี้ยังไง?

Conflict อย่างที่บอกว่าทุกอย่างย่อมมีปัญหาของมัน ซึ่งหนึ่งในการแก้ปัญหานี้ของ Distructured system คือการทำ Consensus algorithm (สนใจก็กดที่ชื่อมันไปอ่านต่อว่าทำยังไงเอานะ ผมอธิบายไว้ในบทความของ Blockchain พื้นฐานไว้ละ)

และจากที่เคยบอกว่า ปัญหา ไม่ได้มีคำตอบเดียวเสมอ และคำตอบแต่ละอันก็จะมีจุดเด่น/ข้อจำกัดที่ต่างกัน ดังนั้นถ้าเรารู้จัก Algorithms หลายๆแบบ เราก็จะสามารถ เลือกสิ่งที่เหมาะสมกับระบบได้อย่างมีประสิทธิภาพ เช่น ในตัวอย่างนี้ถ้าไม่อยากวุ่นวายเราก็สามารถทำ Strong eventual consistency ได้ แต่มันจะเหมาะสมกับหน้างานหรือเปล่า และข้อจำกัดของมันคืออะไร ก็ต้องว่ากันไปตามโจทย์ที่เราเจอ

🎯 บทสรุป

เวลาที่เจอโจทย์ สิ่งที่โปรแกรมเมอร์ควรจะต้องทำไม่ใช่เขียนโค้ด แต่เป็นการมองหา Solution ที่เหมาะกับปัญหา และเลือก Data structure ที่เหมาะสมกับปัญหา + Architecture ที่เจอ แล้วเราจะรู้ขีดจำกัดทางสายเลือดของมัน เพราะโปรแกรมเมอร์ที่เป็นตำแหน่งสูงขึ้นที่แท้จริงคือ ความแม่นยำในการออกแบบและตัดสินใจนั่นเอง

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

ท่องไว้จำจงดี 1 ซอฟต์แวร์ ➡️ มีหลายปัญหา (Problems) 1 ปัญหา ➡️ มีหลายคำตอบ (Algorithms) 1 คำตอบ ➡️ เขียนโค้ดได้หลายแบบ (Data Structure) 1 ปัญหา ➡️ อาจเกิดจากหลาย Context หลาย Domain ดังนั้นตอนที่แก้ปัญหาต้องดูให้ครบทุก Context & Domain มิเช่นนั้น มันจะแก้ตรงนี้ได้ แต่มีปัญหางอกที่จุดอื่นที่เกี่ยวข้องกับมัน

1 คำตอบ ➡️ อาจเป็นวิธีที่ดีที่สุดสำหรับบางสถานะการณ์ และอาจเป็นวิธีที่ห่วยที่สุดในบางสถานะการณ์ก็ได้

1 Data Structure ➡️ อาจะเป็นวิธีที่เร็วที่สุด แต่อาจจะไม่เหมาะสมกับ Architecture ที่ใช้อยู่ก็ได้