29 คะแนน โดย kciter1 2024-10-14 | 6 ความคิดเห็น | แชร์ทาง WhatsApp
  • ซอฟต์แวร์มีหลายสิ่งที่ไม่แน่นอน
  • ทำไมจึงไม่แน่นอน?
    • เหตุผลที่ใหญ่ที่สุดคือความซับซ้อนของธุรกิจ
    • ด้วยความซับซ้อนนี้ สถานการณ์จึงเปลี่ยนแปลงอยู่ตลอด และทำให้การคาดการณ์ของนักพัฒนามีโอกาสสูงที่จะผิดพลาด
    • หอคอยที่สร้างอย่างทุ่มเทพังทลายลงและกลายเป็นหนี้ทางเทคนิคในทันที
    • อีกเหตุผลหนึ่งคือการขาดความรู้และประสบการณ์
    • หากไม่มีความรู้และประสบการณ์ นักพัฒนาอาจสร้างหนี้ทางเทคนิคขึ้นมาเองได้
    • ความซับซ้อนของธุรกิจเป็นปัจจัยภายนอกที่นักพัฒนาไม่อาจควบคุมได้ ขณะที่ความรู้และประสบการณ์เป็นปัจจัยภายในที่นักพัฒนาควบคุมได้
  • สำหรับนักพัฒนา มีอยู่สามเส้นทาง
    • เส้นทางแบบมองโลกในแง่ร้ายที่คิดว่าการต่อสู้กับความซับซ้อนไร้ความหมาย
      • จะเริ่มพูดว่า ‘เดี๋ยวก็เปลี่ยนอยู่ดี ทำๆ ไปเถอะ’, ‘เทคโนโลยีไม่มีความหมายหรอก’
      • เพราะเป็นเส้นทางที่สบายและผ่อนคลาย จึงอาจเลือกเดินทางนี้โดยไม่รู้ตัว
    • เส้นทางที่เพิกเฉยต่อความซับซ้อนและคิดถึงแต่ภาพอุดมคติ
      • เชื่อว่าเทคโนโลยีเพียงอย่างเดียวที่ตนมองว่าเป็นอุดมคติสามารถแก้ได้ทุกอย่าง
      • ทำให้เกิดกรอบความคิดที่แข็งทื่อและเป็นแบบเดียวกันหมด
      • เป็นเส้นทางที่นักพัฒนาหลงเข้าไปได้ง่าย แต่ยากจะหลุดออกมา
    • เส้นทางที่ยอมรับความซับซ้อนและต่อสู้กับมัน
      • แม้ยอมรับว่าไม่มีวันสมบูรณ์แบบ ก็ยังคงพยายามค้นหาแนวทางที่ดีกว่าอยู่เสมอ
      • เป็นเส้นทางที่ยากและต้องอดทน
    • การพัฒนาซอฟต์แวร์ต่อสู้กับความซับซ้อนมาโดยตลอด
      • สถาปัตยกรรม วิธีวิทยา Agile ฯลฯ
      • แล้วสิ่งถัดไปที่จะเกิดขึ้นคืออะไร?
  • การพัฒนาแบบมุ่งสู่การทำลาย
    • เมื่อมองความเป็นจริง ก็ง่ายที่จะตกไปสู่ความคิดแบบสิ้นหวังว่าเดี๋ยวมันก็ถูกลบอยู่ดี
    • เพราะการรู้สึกว่าโค้ดที่เราเขียนอย่างหนักกลายเป็นงานที่ล้มเหลว และต้องลบทิ้งด้วยมือตนเองนั้นเจ็บปวดมาก
    • ถ้าอย่างนั้น ลองคิดกลับกัน แล้วทำให้มันลบได้ดีตั้งแต่แรก จะเป็นอย่างไร?
  • การทำลายเป็นสิ่งที่ดีหรือไม่?
    • หากไม่มีการทำลาย สิ่งใหม่ก็ไม่อาจถือกำเนิดขึ้นได้
    • การทำลายที่พบได้ในซอฟต์แวร์มีอยู่ใหญ่ๆ สองแบบ - pivot และ refactoring
    • Pivot ช่วยให้องค์กรและผลิตภัณฑ์เลือกเส้นทางที่ดีกว่าได้
    • Refactoring เป็นสิ่งจำเป็นอย่างยิ่งเพื่อยืดอายุของซอฟต์แวร์
  • แล้วการพัฒนาแบบมุ่งสู่การทำลายคืออะไร?
    • เป็นวิธีวิทยาการพัฒนาที่ยอมรับข้อเท็จจริงว่าสักวันหนึ่งโค้ดจะถูกทำลาย และพัฒนาโดยมุ่งไปในทิศทางนั้น
    • ยึดหลักใหญ่ 3 ข้อ
      • หากมีความไม่แน่นอน ก็ลดความไม่แน่นอนนั้นลงให้ได้มากที่สุดเท่าที่ทำได้
      • หากเลือกได้หลายวิธี ให้เลือกวิธีที่ทำลายได้ง่ายกว่า
      • คงไว้เฉพาะสิ่งที่จำเป็น ดังนั้นสิ่งที่ไม่จำเป็นให้ลบทิ้งทั้งหมด
    • วิเคราะห์ -> แยกขอบเขต -> ลงมือเขียนโค้ด -> กำจัดความซับซ้อน
    • แก่นสำคัญคือการลดความไม่แน่นอนที่มาจากปัจจัยภายใน และเตรียมพร้อมต่อการทำลายที่เกิดจากปัจจัยภายนอกซึ่งหลีกเลี่ยงไม่ได้
  • การแยกขอบเขต
    • ความไม่แน่นอนคืออัตราการเปลี่ยนแปลง และสามารถใช้สิ่งนี้เป็นพื้นฐานในการแยกได้
    • นักพัฒนาต้องเตรียมรับมือกับปัจจัยภายนอก พร้อมทั้งลดอัตราการเปลี่ยนแปลงที่เกิดจากปัจจัยภายในให้มากที่สุด
    • เนื่องจากอัตราการเปลี่ยนแปลงของแต่ละปัจจัยอาจแตกต่างกันไปในแต่ละองค์กร จึงไม่สามารถแสดงเป็นตัวเลขตายตัวได้ -> ต้องวัดด้วยวิธีเชิงฮิวริสติก
      • ex) การวัด story point
    • ต้องกำหนดระดับนามธรรมว่าจะใช้เกณฑ์ใดในการแยก
  • ความสามารถในการถูกทำลาย
    • เมื่อลงมือพัฒนา ให้เลือกทางที่ทำลายได้ง่ายตามหลักใหญ่
    • สามารถประเมินความสามารถในการถูกทำลายได้โดยพิจารณาจากความเป็นอิสระ ความสามารถในการรับรู้เข้าใจ และความสามารถในการควบคุม
      • ความเป็นอิสระพิจารณาจากระดับของ coupling และ cohesion รวมถึงยึดหลัก single responsibility principle ได้มากน้อยเพียงใด
      • ความสามารถในการรับรู้เข้าใจคือระดับที่นักพัฒนาสามารถมองโค้ดแล้วเข้าใจได้
      • ความสามารถในการควบคุมคือการพิจารณาว่าเป็นพื้นที่ที่นักพัฒนาควบคุมได้หรือไม่
  • การกำจัดความซับซ้อน
    • ต้องตรวจสอบว่ามีสิ่งที่ไม่จำเป็นหรือไม่ และกำจัดมันออกไป กล่าวคือท้ายที่สุดแล้วใน codebase ควรเหลือไว้เฉพาะสิ่งที่จำเป็น
    • หากทำได้ยากเพราะปัญหาเรื่องเดดไลน์หรืออย่างอื่น ก็เพียงบันทึกไว้ก่อนแล้วค่อยจัดการภายหลังก็ไม่มีปัญหา
      • เพราะปัจจัยภายในนั้นควบคุมได้
    • แก่นสำคัญคือการรักษาความเรียบง่ายไว้ให้มากที่สุดเพื่อเตรียมพร้อมต่อการทำลาย
  • เทคนิคของการทำลายโค้ด
    • มีหลักการและวิธีการมากมายในการลบโค้ดให้ดี
    • การแยกเป็นขั้นตอน (refactoring pattern)
    • การรักษา referential transparency
    • การยึดหลัก single responsibility principle
    • การยึดหลัก interface segregation principle
    • Strangler Fig pattern
    • การทำ method specialization
    • การเขียนโค้ดซ้ำ
    • การบันทึกอัตราการเปลี่ยนแปลง

6 ความคิดเห็น

 
annonymous1 2024-10-16

ผมไม่ค่อยเห็นด้วยกับคำพูดที่ว่าหนี้โค้ดเกิดขึ้นเพราะขาดความรู้และประสบการณ์

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

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

-> ธุรกิจมีความซับซ้อน จึงคาดเดาไม่ได้ว่าจะต้องเจอกับสถานการณ์แบบไหน และก็เป็นไปไม่ได้ที่จะศึกษาได้ครบทุกความเป็นไปได้ในแต่ละช่วงเวลา แม้จะไปศึกษาเมื่อเจอสถานการณ์นั้นจริง ๆ แต่ครั้งถัดไปก็อาจเกิดปัญหาใหม่ที่ต่างออกไปโดยสิ้นเชิง จนความรู้นั้นใช้การไม่ได้ก็ได้

 
kciter1 2024-10-16

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

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

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

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

แน่นอนว่า บทความที่ผม/ฉันเขียนก็เป็นเพียงความคิดเห็นของผม/ฉันเท่านั้น ย่อมมีกรณีโต้แย้งได้มากพอ ผม/ฉันคิดว่าการแลกเปลี่ยนความคิดเห็นคือโอกาสที่จะพาเราไปสู่ทางที่ดีกว่า ต่อจากนี้ก็ขอฝากความคิดเห็นกันมาอีกมาก ๆ ด้วยนะครับ/ค่ะ ขอบคุณครับ/ค่ะ

 
annonymous1 2024-10-16

ขอบคุณที่ตอบอย่างกรุณา

 
winterjung 2024-10-14

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

 
savvykang 2024-10-14

ฉันมักจะคิดว่ามีอะไรนอกจากโค้ดบ้างที่อาจหายไปหรือเปลี่ยนแปลงได้ เช่น ข้อมูลหรือสคีมา

  1. ฉันจะพิจารณาว่าโค้ดนั้นอยู่ใน 3 หมวดใดระหว่าง DB schema, โปรโตคอล (เช่น REST API), และฟีเจอร์ โดยสคีมาและโปรโตคอลย่อมแพร่กระจายไปยังโค้ดภายในบริษัทหรือภายนอกอย่างหลีกเลี่ยงไม่ได้ ดังนั้นหากจะเปลี่ยนในภายหลัง ก็ไม่สามารถแก้คนเดียวให้เสร็จภายในไม่กี่วันได้ และจำเป็นต้องมีการทำงานร่วมกัน เพราะฉะนั้นจึงใช้เวลากับขั้นตอนออกแบบมากขึ้นเล็กน้อย
  2. ฉันจะคิดถึง lifecycle และความไม่คงอยู่ของข้อมูลที่โค้ดนั้นจัดการด้วย ดูเหมือนว่าน่าจะรวมถึงสถานการณ์ตอนที่บริการที่คุณ winterjung กำลังกังวลถึงต้องหายไปด้วย การแบ่งประเภทเป็น ledger, transaction, และ history table ที่พูดถึงกันใน OLTP ก็น่าจะเป็นวิธีหนึ่งในการเริ่มต้นคิดเรื่องนี้ได้เช่นกัน
 
kciter1 2024-10-14

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

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