Object/Relational Mapping

    เมื่อเดือนที่แล้วผมได้รับ Visual Studio .NET 2005 Beta 1 ซึ่งมี Code Name ว่า Whidbey หลังจาก Install แล้ว สิ่งแรกที่ผมอยากลองนั่นคือ Object Spaces  ทาง Microsoft ประกาศว่าจะใส่เข้ามาใน Whidbey นี้ แต่ก็ต้องฝันค้างครับ เพราะ Search ใน Help ของ VS.NET ดู ก็ปรากฏว่า มีอยู่หน้าเดียวบอกว่า Document ยังทำไม่เสร็จ ผมเลยไปลองไล่ใน NameSpace ต่างๆ ของ ADO.NET ก็ไม่พบ สุดท้ายก็ต้องพึ่ง Web ครับ ก็ได้ความว่า Microsoft เลื่อนเวลาในการบรรจุ Object Spaces ออกไป จนป่านนี้ก็ยังเงียบอยู่ คนในวงการลือกันว่า Microsoft กำลังรอดูว่าหน้าตาของ EJB 3.0 ของ Sun ว่าจะทำได้ง่ายแค่ไหน ถ้าทำได้ดีอาจจะลอกเลย

    ในความคิดของผม ผมคิดว่า Object Spaces ถือว่าเป็น Technology ที่โดดเด่นที่สุด ในการปรับ Version มาเป็น 2005 จริงๆ ก็ยังมีความสามารถอื่นที่น่าสนใจ แต่ก็ไม่มีตัวไหนเด่นเท่า Object Spaces แถมบางความสามารถ ก็ไม่รู้ว่าคิดเข้าไปได้ยังไง ถ้าไม่ตัดออก ผมจะบ่นให้ฟังจริงๆ ด้วย

    Object Spaces มันไม่ใช่แค่เพียง Library นะครับ มันกระทบถึงแนวทางการพัฒนาโปรแกรมทั้งหมด มันจะทำให้เราเข้าสู่โลก Object-Oriented ได้เต็มตัวจริงๆ การออกแบบโปรแกรมทั้งหมดจะเปลี่ยนรูปไปเลย ผมจะค่อยๆ อธิบายให้ฟังว่า มันเปลี่ยนอย่างไร ค่อยๆ ตามผมมาครับ

    ตอนแรกผมคิดว่าจะรอให้ Microsoft แจกจ่าย Object Spaces ก่อนแล้วมาคุยให้ฟัง แต่พอดีมีคนเขียนถามเข้ามาถึงเรื่องนี้พอดี ผมก็เลยคิดใหม่ว่า คงไม่จำเป็นต้องรอ เขียนเรื่องพื้นฐานให้อ่านกันก่อน พอ Object Spaces มันออกมา เราจะได้รับมือกับมันได้ทันที

    อันที่จริง Microsoft เคยแจกจ่าย Object Spaces รุ่นทดสอบตัวเดี่ยวๆ ออกมาแล้วอย่างน้อย 2 ครั้ง แต่ก็ปิดไปในที่สุด ผมเองก็ไม่รู้ว่าเป็นเพราะอะไร แต่ที่แน่ๆ ก็คือ ใน 2 ครั้งที่รับทราบมานั้น Syntax เปลี่ยนไปมากพอสมควร  วันนี้ผมคงไม่เน้นถึง Syntax ของ Object Spaces เพราะเชื่อว่ารุ่นต่อมาที่แจกจ่ายนั้น คงเปลี่ยนไปอีกไม่น้อย ผู้อ่านคงไม่ได้ประโยชน์อะไรนัก เอาเป็นว่าผมคุยพื้นฐานให้ฟังกัน ซึ่งสามารถนำไปประยุกต์ใช้ได้กับ O/R Mapping ทุกตัวดีกว่า

O/R Mapping - The new technology?

    ถ้าบอกว่า O/R mapping Library เป็นของใหม่ ผมก็คงผิดศีลห้าแน่นอนครับ O/R Mapping Library ไม่ใช่ของใหม่ ทางฝั่งของ Java เขามีมานานมากแล้ว ไล่ไปจริงๆ น่าจะมีเป็นร้อยเจ้าเลยที่ทำ เช่น JDO ของ Sun ถ้าเป็น Commercial ที่ดังๆ ก็มี Toplink หรือ Cocobase ส่วนที่ Open Source นั้นมีมากมายจนนับกันไม่ไหว แต่ถ้าวินาทีนี้ ก็ต้องเขาแน่นอนครับ Hibernate โดยส่วนตัว ที่ลองมาหลายตัวแล้ว ที่ชอบที่สุดก็คือ Hibernate ตัวนี้นี่เอง

    แต่ใช่ว่า O/R mapping Library จะมีแค่อยู่บน Java นะครับ ทางฝั่งของ Microsoft ก็มีมานานแล้วเช่นกัน ตั้งแต่สมัย Visual Basic 6.0 ก็มีหลายตัว แต่ก็ใช้กันในวงแคบๆ เท่านั้น พอเป็น .NET ก็เห็นมีมากขึ้น มีไม่น้อยที่ port มาจาก Object Source ของทางฝั่งของ Java เช่น NHibernate หรือ OJB.NET เป็นต้น และในที่สุด Microsoft ก็ทนกระแสไม่ไหว ก็ต้องประกาศตัว Object Spaces ออกมา ประมาณ 1 ปีแล้วครับ ซึ่งเป็นการทำหมันพวก Open Source ที่ port มาทางฝั่งของ Java กลายๆ ครับ เพราะมีคนไม่น้อยครับ ที่ลังเล สุดท้ายก็เลือกที่จะรอทาง Microsoft แต่ทาง Microsoft ก็เล่นไม่ออกตามที่กำหนด วันนี้ผู้คนไม่น้อยก็กำลังอึดอัดกันอยู่

    แล้ว O/R Mapping มันคืออะไรกันแน่?     เขียนไปตั้งนานยังไม่บอกเลยว่า O/R Mapping จริงๆ แล้วมันคืออะไร ก่อนที่ผมจะเฉลยให้ฟัง ผมขอท้าวความก่อนครับ (เล่นยืดเรื่องเหมือนละครบางช่อง)

R for Relational Database

เรามาเริ่มกันที่ Relational ในคำของ O/R Mapping มันคือก็คือ Relational Database นั่นเอง  Database ที่กำเนิดมาจาก แนวคิดของ Dr. Codd ซึ่งกำเนิดมาตั้งแต่ ปี 1970 ซึ่งมากกว่า 30 ปีแล้ว

    ด้วยความเสถียรของระบบ เพราะพัฒนากันมานานกว่า 30 ปี มันผ่านบทพิสูจน์กันมาจนนับไม่ถ้วน ใครจะเอา Technology อื่นมาใช้ ก็ต้องคิดหนักมากครับ ยิ่งไปกว่านั้น Dr. Codd เมื่อสมัยสร้าง Relational Database นั้น เขาก็สร้างภาษา SQL ขึ้นมาเป็นคู่แฝดอภินิหาร (เลิกอ่านว่า se-quel ตาม Microsoft เถอะครับ มันชื่อว่า S-Q-L) ด้วยภาษา SQL ทำให้เราสามารถจับแพะชนแกะ ทำ Ad-hoc Report ด้วยความเร็วที่เร็วมาก ที่เร็วได้นั้นไม่เกี่ยวกับ Dr. Codd โดยตรง แต่หากเป็น Algorithm ที่คิดค้นเพิ่มเติมมาในช่วงเวลา 30 ปี ก็ Big 5 ของวงการ ก็คือ Informix, Oralcle, Sybase, DB/2 และ MSSQL ต่างก็ลอก Algorithm ซึ่งกันและกัน เมื่อ  SQL Serverได้รับคำสั่ง SQL แล้ว Algorithm ตัวนี้ก็จะทำทุกวิถีทางที่ดึงคำตอบออกมาให้ได้เร็วที่สุด ทุกวันนี้ เรามีความเชื่อที่ค่อนข้างจะคลาดเคลื่อนกับความเป็นจริงอยู่มาก ใครใช้ DB/2 อยู่ก็จะถูกกรอกหูจาก Vendor ว่า DB/2 นี้เร็วที่สุด ส่วนทาง Oracle ก็เช่นกัน ผมเองพอไปคุยกับเพื่อนๆ ในวงการ ก็ได้รับข้อมูลทำนองว่า Database ที่เขาใช้ เร็วกว่า Big 5 ตัวอื่นเป็น 10 เท่า นั่นคือความรู้สึกครับ แต่ความจริงจากที่ผมทดสอบเอง และที่อื่นทดสอบเช่น tpc.org นั้น ยืนยันครับว่า Big 5 แต่ละตัวนั้น ความเร็วไม่แตกต่างกันมาก พลัดกันขึ้นมาเป็นผู้นำอยู่เสมอ ถ้าเอาวินาทีที่เขียนบทความนี้ Oracle 10g ซึ่งเป็นตัวใหม่ล่าสุดของทาง Oracle ทำคะแนนนำ MSSQL 2000  ประมาณ 20-30%  เปอร์เซ็นนะครับไม่ใช่จำนวนเท่า แต่ก่อนหน้านั้น Oracle 9i ไม่ได้ดีกว่า MSSQL ครับ รอดู MSSQL 2005 ครับ ใครใหม่ก็เร็วกว่า ถ้าออก Version ใหม่มาแล้วขึ้นนำใน tpc.org ไม่ได้ แบบนี้เรียกว่าเสียรูปมวย ซึ่งผมเชื่อว่า คงไม่มีใครยอมใครครับ

    สิ่งที่เราให้ความสนใจที่สุดในการเพิ่มความเร็วของโปรแกรม ก็คือคำสั่ง SQL ครับ SQL Server ตัวไหนก็ตาม มันมีพื้นฐานเหมือนกัน ก็คือใช้โครงสร้างตระกูล B-Tree ด้วยกันทั้งนั้น สิ่งที่ SQL Server เก่งก็คือ การงมเข็มในมหาสมุทร คุณมี Records มาระดับเป็นล้าน Record ก็ตาม ถ้าคุณค้นหาข้อมูล ที่ได้คำตอบออกมาน้อยๆ เช่นรายการเดียว มันจะเร็วมาก กระพริบตาก็เสร็จ แต่ในงานจริงๆ แล้วมันไม่ง่ายอย่างนั้น เรามักจะพบว่า โปรแกรมทำงานช้ากว่าระดับที่ยอมรับได้ คนส่วนมากจะเริ่มต้นที่ เปลี่ยนฐานข้อมูล ไปใช้ยี่ห้อที่มีความเชื่อว่าจะเร็ว หรือไม่ก็เปลี่ยนเครื่องให้มันเร็วขึ้น มีปรมาจารย์ทางฐานข้อมูล ถ้าผมจำไม่ผิดน่าจะเป็น Joe Celko กล่าวทำนองว่า "ถ้าคุณเลือกที่จะเปลี่ยนเครื่อง อย่างเก่งก็ทำให้มันเร็วขึ้นได้ร้อยเท่า แต่ถ้าคุณเลือกที่จะเปลี่ยนการเขียนโปรแกรมของคุณ คุณสามารถทำให้มันเร็วได้เป็นล้านเท่า" เรื่องนี้ผมเห็นด้วยเป็นอย่างยิ่ง เพราะผมประสบด้วยตัวเองเลย ผมขอแนะอย่างนี้ก็แล้วกัน ถ้าคุณอยากให้โปรแกรมทำงานเร็วขึ้น คุณต้อง

  1. เขียนโปรแกรมสอดคล้องกับธรรมชาติของ SQL Server

  2. ออกแบบโครงสร้างฐานข้อมูลให้เป็น ยึดหลัก Normalization

  3. เขียนคำสั่ง SQL ที่ซับซ้อนให้เป็น เพื่อความเร็วสูงสุด

    แนวทางการออกแบบโปรแกรมสำหรับ Relational Database  นั้น ก็จะเริ่มเขียนโปรแกรมได้ เราต้องเริ่มจากการนิยามโครงสร้างของ ฐานข้อมูลกันก่อน เรามักจะใช้ E-R Diagram เป็นเครื่องมือช่วย ใครไม่ใช้ก็ไม่ผิดกติกาแต่อย่างใด คราวนี้มาถึงความเชื่อที่สองที่เชื่อกันผิดๆ มีคนมักจะกล่าวว่า ที่ Dr. Codd นั้นคิด Normalization นั้นเป็นเรื่องทางทฤษฏี โบราณมาก เอามาใช้กับชีวิตประจำวันไม่ได้ ผมเดาได้เลยครับว่า คนที่พูดประโยคเช่นนี้ ยังไม่เข้าใจแนวคิดของการทำ Normalization อย่างแท้จริง ผมเล่าให้ฟังอย่างนี้ดีกว่า

    ศาสตร์ของคอมพิวเตอร์นี้ผูกพันอยู่กับเรื่องสองเรื่อง นั่นคือ คณิตศาสตร์และอีเลคโทรนิค คณิตศาสตร์เอาไว้ใช้กับ Software ส่วนอีเลคโทรนิคนั้นมีไว้สำหรับ Hardware ในยุคอดีตที่คิดค้นเครื่องคอมพิวเตอร์นั้น เราใช้ในการรณรงค์สงครามครับ เช่นใช้ในการคำนวณนำหนักบรรทุกระเบิดให้อยู่ในจุดที่เหมาะสมที่สุด หรือใช้ในการคำนวณการถอดรหัสของทางฝั่งตรงข้าม ซึ่งจะเห็นได้ว่ามันเกิดขึ้นเพราะการคำนวณนี้เอง มันจึงได้ชื่อว่าคอมพิวเตอร์ หรือเครื่องคำนวณนั่นเอง ในโลกยุคปี 70 นั้น คอมพิวเตอร์เริ่มผันตัวเองออกจากงานคำนวณทางคณิตศาสตร์ มาสู่ระบบธุรกิจ ยุคสองคนสองคม FORTRAN และ COBOL  ตัว FORTRAN สำหรับงานคำนวณ ส่วน COBOL สำหรับงานธุรกิจ  แต่ในยุคปี 70 นั้น โลกคอมพิวเตอร์ ยังเป็นโลกของคณิตศาสตร์ ทุกอย่างต้องนิยามโดยใช้คณิตศาสตร์ Relatioanl Database ก็เช่นกัน แนวคิดพื้นฐานนั้น Dr. Codd ได้มาจากเรื่องทางคณิตศาสตร์ คือ Set และ Relational Calculus ดังนั้น Dr. Codd จึงนิยามทุกอย่างโดยใช้ภาษาคณิตศาสตร์

    ทุกวันนี้การเขียนโปรแกรมอย่างน้อยก็ด้านการเขียนโปรแกรมธุรกิจ (Enterprise Application) นั้นเราไม่จำเป็นต้องเรียนรู้คณิตศาสตร์ในแบบนั้นอีกแล้ว ผมเองก็เจอโปรแกรมเมอร์เก่งๆ หลายคน เขียนงานทางธุรกิจได้ดี แต่ความรู้คณิตศาสตร์เข้าขั้นแย่มาก! ความซับซ้อนของคณิตศาสตร์มันถูกเครื่องมือต่างๆ ซ่อนไว้จดหมด

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

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

    ทีแรกผมตั้งใจว่าจะอธิบายเรื่อง Normalization ให้ฟัง แต่มันคงเป็นการเอามะพร้าวห้าวมาขายสวน ประกอบกับมันจะขัดกับแนวคิดของ O/R Mapping เพราะ แนวคิดของ O/R Mapping นั้น มันไม่ Normalize เอาเสียเลย ก็เลยของดเอาไว้ก่อน

Top-down Programming กับ ฐานข้อมูล

    เราเขียนโปรแกรม ไม่ว่าคุณจะใช้ Windows Form, Visual Basic, Swing, SWT หรือ Web Programming ใดๆ ก็ตาม ตราบใดที่ คุณเน้นเขียน Code ทั้งหมดอยู่ใน Event มันก็ยังเป็น Top-down Programming อยู่ดี อย่าเข้าใจผิดว่าเราใช้ UI ที่เป็น Object-Oriented แล้ว มันจะทำให้โปรแกรมของเรากลายเป็น Object-Oriented ไปโดยปริยาย มันไม่ใช่ครับ เพราะชื่อมันก็บอกอยู่แล้วว่า คุณออกแบบหรือเขียนโปรแกรมจากบนลงล่าง จาก Form ไล่ไปสู่ Database แต่ถ้าโปรแกรมเป็น Object-Oriented จริงๆ แล้ว มันต้องไล่จากข้างล่างขึ้นข้างบน หรือ Bottom-Up Programming อาจจะกล่าวได้ว่า มันต้องไล่จาก Database ขึ้นมาสู่ UI

    ใช่ว่า Top-down Programming จะไม่ดีนะครับ เรามีงานใหญ่ๆ ที่ใช้วิธีนี้แล้วสำเร็จก็มากมาย ผิดกลับ Object-Oriented ที่บอกว่ากันว่าดี ผมเห็นไปไม่รอดก็เยอะ หัวใจสำคัญมันอยู่ที่เรารู้เท่าทันเครื่องมือที่เราใช้หรือไม่ต่างหาก

    ผมขอย้อนประวัติการเขียนโปรแกรมฐานข้อมูลในอดีตก่อน ไม่ใช่เพียงเพื่อให้มันดูยาวนะครับ มันเกี่ยวเนื่องกันจริงๆ ผมขอเริ่มต้นที่ COBOL หรือยุคใหม่หน่อยก็เป็นพวก xBase อย่าง dBase, Clipper หรือ Fox รุ่นแรกๆ พวกนี้ล้วนแล้วแต่มีภาษาโปรแกรมเฉพาะ  มีแนวคิดของ Table เหมือนกับใน SQL Server  แต่การเก็บนั้นเขาเก็บ 1 Table ต่อ 1 แฟ้มข้อมูล  แต่เขาไม่ใช้คำสั่ง SQL ในการเข้าถึงข้อมูลนะครับ เขาใช้แนวคิดของ Cursor ในการเข้าถึงข้อมูล นั่นก็คือ เขามองข้อมูลที่เข้าไป มีลำดับก่อนหลัง เข้าไป Record แรก ก็จะได้เลขหนึ่ง เข้าต่อมาก็จะได้เลขสองตามลำดับ เราสามารถเขียนโปรแกรมเพื่อไปยังรายการบรรทัดใดก็ได้ อาจจะใช้คำสั่ง goto 15 เพื่อไปยังบรรทัดที่ 15 เป็นต้น   ถ้าต้องการความเร็ว เขาใช้วิธีการสร้าง Index โดยมากจะเป็นแฟ้มแยกต่างหาก Index ที่กล่าวมานี้มันก็ใช้โครงสร้างตระกูล B-Tree นั่นแหละครับ เหมือนในพวก SQL Server ต่างๆ ดังนั้น ถ้าเราค้นหาข้อมูลตาม Index มันจะเร็วมาก แต่คุณจะเห็นจุดอ่อนของมันได้ทันที เพราะเครื่องมือเหล่านี้ มันมอง Table ต่างๆ แยกออกจากกัน มันไม่มีคำสั่งวิเศษอย่าง SQL มีจับเอาข้อมูลของหลาย Table มา Join กันเพื่อให้ได้งาน ทางออกในสมัยนั้นคือ เมื่อ Join อัตโนมัติไม่ได้ก็ต้อง Join มือกันครับ ลองดู Code นี้

sumofABC.prg

LOCAL customerid, orderid, sum

sum := 0

USE customers INDEX custname NEW
FIND "ABC Co.,LTD"
IF eof()
    ? "Not Found"
    EXIT
ENDIF

customerid := customers->customerid

USE orders INDEX customerid NEW
FIND customerid
DO WHILE .NOT. eof()
    orderid := orders->orderid
    USE orderlines INDEX orderid NEW
    FIND orderid
    DO WHILE .NOT. eof()
        sum := sum + (orderlines->unitprice * orderlines->quantity)
        SKIP
    ENDDO
    SKIP
ENDDO
? sum

    Code นี้ตั้งใจเขียนโดยใช้ Syntax ของ Clipper แต่เนื่องจากผมไม่ได้ใช้มันมากกว่า 10 ปีแล้ว ถ้าผู้รู้ Clipper มาอ่านจริงๆ อาจจะเห็นว่ามันผิด ก็อย่าว่ากันนะครับ

    Code นี้เราต้องการหาดูว่าบริษัท ABC นี้เคยซื้อของของเรารวมแล้วเป็นยอดเท่าไร ถ้าใครเขียน SQL เป็น งานนี้เขียนเป็น SQL คำสั่งเดียวได้เลย ซึ่งมีการ join 3 tables เข้าด้วยกัน นั่นคือ customers, orders, orderlines แต่ในกรณีเราไม่มีคำสั่ง SQL ให้ใช้ เราก็ต้องใช้ Flow Control เพื่อเข้าหา Table ที่ละตัวเอง แต่โปรแกรมนี้ไม่ช้านะครับ เพราะเราใช้คำสั่ง Find ที่ดึงเอา Index แบบ B+-Tree มาใช้ บางครั้งเราเรียกการเก็บ Table กับ Index แยกกันแบบนี้ว่า ISAM    

    วิธีการที่ใช้ผลลัพธ์ที่ได้จาก Table หนึ่งเพื่อไปดึงเอาข้อมูลของ Table ต่อไปออกมา (ในกรณีนี้ 3 ต่อ) บางครั้งเราเรียกวิธีการเขียนโปรแกรมแบบนี้ว่า Table-Oriented Programming หรือ TOP แต่ปัญหาของวิธีนีก็คือ ถ้าเราใช้หลักการของ Relational Database เต็มรูปมาใช้ มันจะต้องเกิดการ Join ด้วยมือเป็นจำนวนมาก ลองนึกภาพง่ายๆ ดูว่า ถ้าเขียนโปรแกรม  ดึงเอาข้อมูลของ พนักงานออกมาแสดง มันต้อง Join ไปที่หาข้อมูล จังหวัดที่เกิด, ตำแหน่ง, ประวัติการศึกษา, ศาสนา และอื่นๆ อีกมาก ทำให้การเขียนโปรแกรมแบบนี้ค่อนข้างยุ่งยาก โดยมากแล้ว เขามักจะ De-normalize ทำให้ลดจำนวนการ Join ลง บางคนใช้วิธีไม่ต้อง Join เลย กลายเป็นทุกอย่างอยู่ใน Table เดียว ที่เรียกว่า Flat File แต่การทำอย่างนั้นอันตราย จะเกิดปัญหามากมาย

    จนกระทั่งมีการนำเอาคำสั่ง SQL ผสมเข้าไป Host Language อย่าง C, VB หรือ Java กลายเป็นรูปแบบที่เราคุ้นเคย ผมเองตอนสมัยเรียน SQL ใหม่ เมื่อปลายยุค 80 ผมตั้งคำถามให้กับตัวเองว่า SQL มันเอาไปใช้ทำอะไร  ในมหาวิทยาลัยก็สอนกันจัง ภาษานี้ไม่มี Flow Control เลย แน่นอนเขียนโปรแกรมแบบเต็มรูปก็ไม่ได้ ดูเหมือนว่ามันทำงานได้แค่จัดการกับข้อมูลเท่านั้น จะว่าให้ User เอาไปใช้ ผมก็ว่ามันไม่เหมาะสม มันต้องเป็น Power User จริงๆ ช่วยไม่ได้ครับ ความคิดของผมตอนนั้นมันถูกจำกัดด้วยแนวคิดของ Table-Oriented Programming

SQL as an embedded Language

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

    แนวคิดของการแทรก SQL เข้าไปใน Host Language นั้น นิยมกันต้นยุค 90 ซึ่งเป็นยุคเสื่อมของ Table-Oriented Programming เพราะมันไม่สามารถรองรับ Client/Server ได้ดีพอ แต่นั่นแหละครับ คนที่เข้ามาใช้ SQL กันในยุคนั้น ก็โอนย้ายกันมาจาก Table-Oriented Programming กันทั้งนั้น การเขียนโปรแกรมก็ยังติดยึดกับของเดิม นั่นคือดึงทุกอย่างมาให้ Host Language เป็นตัวทำงาน ซึ่งการทำเช่นนั้นกับ Network ทำให้มันเกิดสิ่งที่เรียกว่า Round-Trip ข้อมูลต่างๆ จะเดินพาเหรดมายังเครื่องของเราเพื่อให้เราประมวลผลและปรับปรุง จากนั้นก็เดินพาเหรดกลับไปบันทึกที่ฐานข้อมูล นอกจากมันจะช้ามากแล้ว มันยังทำให้เกิดการ Lock Record มหาศาล

    เมื่อใช้ SQL ก็ต้องใช้แนวคิดใหม่ครับ คือ Logic ต่างๆ แทนที่จะไปเก็บว่าที่ Host Language กลับไปเก็บไว้ในคำสั่ง SQL เอง แบบนี้ทำงานเร็วขึ้นมาก แต่มันก็ทำให้ SQL ซับซ้อนขึ้น ถึงแม้ว่าจะมีการคิดค้น Stored Procedure ที่เพิ่มเติมความสามารถของภาษา SQL ขึ้นมาให้มี Flow Control แต่มันก็ยากอยู่ดี สุดท้ายก็คือ ความซับซ้อนครับ ใครบอกว่า SQL ง่ายผมขอเถียงเลยครับ  ถ้าคุณเคยทำงานขนาดใหญ่ๆ การที่จะพบคำสั่ง SQL ที่มีแค่คำสั่งเดียวคือคำสั่ง Select ที่มีขนาดยาว 5-6 หน้ากระดาษ ถือเป็นเรื่องปกติครับ ปัญหามันไม่ได้อยู่ที่ตอนเขียนครับ แต่หากอยู่ที่การ maintain code ปวดหัวอย่าบอกใครเชียว

    ยังครับ ปัญหายังไม่หมด การเขียน SQL นั้นผูกพันโดยตรงกับฐานข้อมูล ดังนั้น ถ้ามีอะไรเปลี่ยนแปลงไปยังฐานข้อมูล โปรแกรมที่เรียกใช้ทุกต้วต้องกระทบหมด เช่น ถ้าเราเปลี่ยนชื่อ field ใน table เราต้องแก้หลายโปรแกรมเลย Business Logic มันกระจายไปอยู่ตามโปรแกรมต่างๆ เมื่อมีการเปลี่ยนแปลงเกิดขึ้น ก็แน่นอนครับ ต้องกระทบหลายที่เป็นธรรมดา

    ถ้าใครคุ้นเคยกับ Object-Oriented จะพบว่า แค่ตัวแปรตัวเดียวเรากำหนดให้เป็น public ใน class ถ้าคุณทำอย่างนั้น ถูกครูตีมือแน่นอนครับ เพราะตัวแปรตัวนั้นไม่มีตัวป้องกัน ใครข้างนอกมาใส่ค่าอะไรก็ได้ ทำให้หาที่ผิดยากมาก เพราะ error มันจะไม่ฟ้องในทันที แต่หากมันจะทอดเวลายาวไป เมื่อเอาค่าที่ใส่ผิดไปคำนวณหลายต่อแล้ว ได้ผลลัพธ์สุดท้ายผิด ต้องค่อยๆ ไล่หาย้อนกลับมาถึงต้นตอ ซึ่งไม่ง่ายเลย แต่เวลาคุณใช้งาน Relational Database โดยโปรแกรมแต่ละตัว ยิ่งคำสั่ง SQL เข้าไป แบบนั้นถ้าเทียบเคียงกับที่ผมกล่าวมาข้างต้น จะเห็นว่าข้อมูลทุกตัวในฐานข้อมูลกลายเป็นเหมือนตัวแปร public โปรแกรมไหนจะแก้ไขอะไรก็ได้ แก้ผิดแก้ถูกเราก็ไม่อาจรู้ น่ากลัวมากครับ แต่ก็นั่นแหละครับ อย่างที่ผมกล่าวไว้ข้างต้น ถ้าใครรู้เท่าทันปัญหา ก็สามารถลดปัญหา ให้อยู่ในระดับที่ควบคุมได้ครับ

    จากปัญหาข้างต้น ทำให้เกิดกระแสการต่อต้าน SQL โดยเฉพาะอย่างยิ่งทางฟากของ Java มีคนหัวก้าวหน้าจำนวนไม่น้อยที่บอกว่า SQL นั้นอันตราย คล้ายกับที่ Dijkstra เคยบอกเราเมื่อหลายสิบปีก่อนว่า คำสั่ง goto นั้นอันตราย หลายคนพยายามจะพิสูจน์ว่า เราสามารถเขียนโปรแกรมขนาดใหญ่ได้โดยไม่ต้องพึ่งคำสั่ง SQL เลย แต่ที่ผ่านมาทาง Microsoft ไม่สนใจครับ ทุกสิ่งทุกอย่างผูกพันกับ Relational Database กันอย่างเต็มที่ โดยเฉพาะอย่างยิ่ง Microsoft ทุ่มกำลังพัฒนา ADO.NET จนกลายเป็น Library สุดยอดในการเข้าถึงฐานข้อมูลแบบ Relational Database นี่เป็นครังแรกครับ ที่ Microsoft ให้ความสนใจกระแสการไม่ใช้ SQL ก็คือ Object Spaces นั่นเอง

O for Object-Oriented

    หลังจากผ่านพ้นยุครุ่งเรืองสุดขีดของ SQL เมื่อกลางยุค 90 ก็มาถึงยุคของ Object-Oriented ที่จริงมันก็เก่าแก่พอกัน คือมากกว่า 30 ปีแล้ว แต่ด้วยหลายปัจจัยที่ผมคงไม่มากล่าวในที่นี้ ทำให้ Object-Oriented เพิ่งได้รับความนิยม ผมขอเน้นเฉพาะ Object-Oriented สำหรับงานธุรกิจเท่านั้นนะครับ ในวงการอื่นผมเองไม่มีประสบการณ์พอจะกล่าวถึง

    ผมเองก็เขียนเรื่อง Object-Oriented มาพอสมควรใน Web Site นี้ มาวันนี้ผมขอขยายต่อไปถึงเรื่องการกับฐานข้อมูล แต่ก่อนจะไปถึงตรงนั้น เรามาทบทวนวิธีการออกแบบโปรแกรมโดยใช้ Object-Oriented กันก่อน

    ไม่ว่าคุณจะใช้ Methodology ตัวใดก็ตาม ทาง Methodogies นั้นๆ อาจจะใช้ Use-Case หรือ CRC หรือ Artifact ใด้ก็ตามที่ไม่ค่อยจะเหมือนกันนัก ถึงแม้ว่าจะใช้ UML ก็เป็นส่วนใหญ่ กระนั้นก็ตามก็ไม่ค่อยจะลงรอยกันนักว่าจะใช้เครื่องมืออะไร และเรียงลำดับเครื่องมือก็ไม่ค่อยจะแนวเดียวกันนัก แต่มีอยู่สิ่งหนึ่งครับ ที่ผมเห็นว่าเหมือนกันทุก Methdology นั่นก็คือ Class Diagram ไม่ว่าจะผ่านกันมาอย่างไร ภาพสุดท้ายในกระดาน ก็มักจะเป็น Class Diagram อย่างหลีกเลี่ยงไม่ได้

    ถ้าผมกล่าวว่าเป้าหมายของการออกแบบโปรแกรมแบบ Object-Oriented คือให้ได้ Class Diagram พร้อมความสัมพันธ์ระหว่าง Class ก็คงจะไม่คลาดเคลื่อนกับความเป็นจริงนัก คุณเห็นภาพอะไรไหมครับ ถ้าคุณใช้การเขียนโปรแกรมแบบเดิม ไม่ว่าจะเป็น Table-Oriented Programming หรือ Relational Database โดยใช้ Top-Down Programming ก็ตาม ภาพสุดท้ายที่ได้ก็คือภาพของ Table ต่างๆ ซึ่งมีความสัมพันธ์ ซึ่งแน่นอนครับ ภาพมันเป็นคนละภาพกับ Object-Oriented เลย

    แนวทางของการออกแบบ Object Oriented นั้น เมื่อเรามองความสัมพันธ์ต่างๆ ออกเป็น class ต่างๆ แล้ว เราต้องกำหนดความสัมพันธ์ให้มันด้วย

 

    จากภาพนี่เป็น Class Diagram อย่างย่อ ซึ่งจริงๆ (ไม่แสดง Attributes และ Operation) ภาพนี้ไม่ค่อยนิยมเขียนแบบนี้เท่าใดนัก ปกติแล้วเขาจะเอา OrderLine ให้มันเป็น Associate Class ไม่ใช้ Composite ลักษณะนี้ แต่ไม่เป็นไรครับ เอาแบบดูแล้วเข้าใจง่ายๆ แบบนี้ดีแล้ว

    บางคนอาจจะใหม่กับ class Diagram อาจจะมองไม่ออกว่า มันกลายเป็น Object ได้อย่างไร ผมเลยวาด Object Diagram ให้ดูอย่างนี้ครับ

   

    จากภาพนี้จะเราจะเห็น Object ที่เกิดขึ้นในหน่วยความจำ มีข้อสังเกต ดังนี้ครับ

  1. Product ทั้งสามนี้ สามารถนำไปใช้กับ Order ใบอื่นได้ เช่นถ้าต้องการใช้ปากกา ก็ต้องไม่ new object ของ ปากกาขึ้นมาใหม่นะครับ ต้องใช้ของที่มีอยู่แล้วเท่านั้น

  2. ถ้าสังเกตจาก Class Diagram ผมวาด ลูกศรไว้ด้วย ลูกศรดังกล่าวนี้เรียกว่า Navigation ครับ เป็นการเก็บตัวชี้ (ตัวแปร Reference) เช่น Order ชี้ไปยัง Customer นั่นหมายความว่า ใน Class ของ Order นั้น มีนิยามแบบนี้ครับ

            class Order {  private Customer _cust; ... }

        ดังนั้นเมื่อเราได้ Object ของ Order มา เราสามารถ Navigate ไปยัง Object ของ Customer ได้ ในที่นี้ เมื่อเรารู้ Order JC00001 เราจะรู้ทันทีว่า ผู้สั่งก็คือ         ลูกค้าชื่อ ABC Co., Ltd. นั่นเอง

    3.   บางคนอาจมองดูแล้วเหมือนกับ World-Wide Web ที่แต่ละหน้าสามารถ Link ไปยังหน้าอื่นได้ มองอย่างนั้นก็ไม่ผิดกติกาแต่อย่างใด มีคนเคยกล่าวว่า ถ้าเราเข้า Website ได้สักที่หนึ่ง เราสามารถ Navigate ไปยัง Web Site อื่นๆ ตั้งแต่เช้าจรดเย็นไม่ซ้ำที่เลย โดยไม่ต้องกด Keyboard แม้แต่ตัวเดียว ใช้เพียง mouse แล้ว click link ไปเรื่อยๆ หลักการของ Object นี้ก็เป็นเช่นเดียวกันครับ เมื่อเราเข้าไปที่ Object หนึ่งแล้ว เราสามารถที่จะ Navigate ไปยัง Object อื่นได้เรื่อยๆ ซึ่งต่างกับ SQL ที่เราเขียนกันมา เมื่อคุณดึงข้อมูลมาแล้ว คุณจะดูได้เฉพาะที่คุณดึงมาเท่านั้น ถ้าต้องการดูข้อมูลอื่นอีก ก็ต้องไปสร้างคำสั่ง Select ใหม่ ไม่มีแนวคิด Navigation แบบนี้ครับ

    4.   ถ้าจะว่ากันไปแล้ว ใครคุ้นกับภาษา C การเก็บข้อมูลแบบนี้ดูเหมือน Linked-Link จริงๆ แล้วหลักการมันก็ไม่หนีกันครับ

    5.   รูปที่ให้ดูนั้นเป็นแบบง่ายเท่านั้น ผมไม่ได้แสดงภาพของ Interface, Inheritance หรืออื่นๆ ให้เห็น เพราะเกรงว่าจะสับสน

    6.   ถ้าพิจารณาความสัมพันธ์ของ Order กับ OrderLine จะเห็นว่า มันมีความสัมพันธ์แบบ One-to-many และยังมีการทำ Navigate อีก นั่นหมายความว่าใน Object ของ Order จะเก็บตัวชี้ไปยัง OrderLine ทุกตัว ซึ่งมันอาจจะเป็น Array หรือ Collection แบบอื่นก็ได้ เช่น class Order { private OrderLine[] _orderlines; }

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

Persistence

    ความฝันของนักวิทยาศาสตร์คอมพิวเตอร์ในการทำให้ Object-Oriented ให้มันมีความสามารถทางฐานข้อมูล โดยตั้งโจทย์ว่า ถ้าเครื่องเรามีหน่วยความจำเหลือเฟือ พอจะเก็บข้อมูลไว้ได้ทั้งหมดไว้ใน Object ต่างๆ ดังตัวอย่างข้างบน ถ้าเครื่องนั้นไม่มีวัน Hang ตัว Objects ต่างๆ จะมีสภาพเป็นเหมือนกับฐานข้อมูลตัวหนึ่งเลยทีเดียว แต่เราก็รู้กันว่ามันเป็นไปไม่ได้ ดังนั้นนักวิทยาศาสตร์คอมพิวเตอร์เลยคิดใหม่ว่า แล้วถ้า Object นั้นเกิดปิดเครื่องแล้ว Object ต่างยังคงอยู่ ไม่ตาย แบบนี้ก็พอถือว่าเป็นฐานข้อมูลได้เหมือนกัน การที่ทำให้อายุของ Object นั้นมันยาวเลยอายุของตัวโปรแกรมที่สร้างมันและเรียกใช้มัน เราเรียกว่า Persistence

    ผมเจอคำว่า Persistence ครั้งแรก สมัยที่อ่านหนังสือ Object-Oriented analysis and design with applications ของปรมาจารย์ Grady Booch ในหนังสือมีรูปคนกำลังลากแมวที่กำลังวิ่งหนีเข้าไปในถัง แล้วอธิบายว่านี่คือ Persistence ผมก็หน้ามืดครับ พอเข้าใจว่าปิดเครื่องแล้ว Object ไม่ตาย แต่ไม่เข้าใจว่า มันจะมีอายุอยู่เลยโปรแกรมที่เรียกใช้ไปเพื่ออะไรกัน ผมหาเหตุผลไม่ได้ ก็ช่วยไม่ได้ครับ กรอบความคิดของผมในตอนนั้น คำว่าฐานข้อมูลต้องหมายถึง Relational หรือ Table-Oriented Programming เท่านั้น เอา Object ไปเก็บเป็นข้อมูล ผมนึกภาพไม่ออกจริงๆ กว่าจะรู้เรื่องก็ต้องใช้เวลาเป็นปีครับ

    ในยุคแรกของการทำ Persistence นั้น เราใช้หลักการที่เรียกว่า Serialization เป็นการเอา Object มาเข้า Stream เก็บ byte ต่อ byte เข้าไปใน Array  หรือ save ไว้เป็นแฟ้มก็ได้ คล้ายกลับแฟ้มรูปภาพ พอเวลา save เสร็จแล้ว เราจะปิดเครื่องก็ไม่ว่ากัน พอเปิดเครื่องใหม่ เราสามารถ load จากแฟ้ม เข้ามายัง Object ได้เหมือนเดิม นี่คือรูปแบบ Persistence อย่างง่าย ให้ผมจินตนาการ ผมนึกถึงหลุมดำหรือนาฬิกาทรายดู พอใครหล่นเข้าไปในกรวยนั้น ที่ปลายกรวย ตัวเราจะยืดออก ยาวออกมาเป็นเส้นด้าย จากนั้น เราจะค่อยๆ รวมตัวกันอีกที่หลุมดำอีกฟากหนึ่ง ตอนที่เรายืดตัวนั่นแหละครับคือ Serialization

    อย่าเพิ่งคิดว่าเรื่อง Serialization เป็นง่ายๆ ไม่มีอะไรซับซ้อนนะครับ ลองคิดตามดู เมื่อ Object ถูก load เข้ามาใหม่ มัน Load เข้ามาที่ใหน ถ้ามันไม่ Load เข้าที่เดิม การที่เราทำตัวชี้ มันจะชี้ผิดที่หมดเลย ยิ่งไปกว่านั้น เราพูดถึงแค่การเก็บ แล้วการค้นหาข้อมูล จะค้นข้อมูลแบบ Adhoc ได้อย่างไร ในเมื่อเราไม่มีคำสั่ง SQL อีกแล้ว ผมจะค่อยๆ เฉลยไปทีละนิดครับ

    ผมขอนอกเรื่องหน่อย ทาง Microsoft เคยฝันไว้ในตอนสร้าง COM+ ครับ คือทาง Microsoft ต้องการให้มี Relational Database ขนาดเล็กๆ อยู่บนเครื่อง Desktop เลย ผมไม่ได้หมายถึง MSDE นะครับ แต่หากเป็น ฐานข้อมูลทั้งตัวที่อยู่ใน Memory ปิดเครื่องก็หาย ทาง Microsoft เคยเรียกว่า IMDB (In-Memory Database) แต่จนแล้วจนรอดก็ไม่ได้บรรจุเข้าไปใน Windows 2000 ครับอย่างที่ตั้งใจครับ หายไปเลย จนกระทั่ง เกิด .NET ผมเห็น Microsoft ปลุกผี IMDB มาใหม่ภายใต้ชื่อว่า ADO.NET ครับ ส่วนของ DataSet หรือ DataTable นั่นแหละครับ คือ IMDB

    วกกลับเข้ามาอีกที อย่าเพิ่งคิดว่าผมเพี้ยนนะครับ เรื่องของ Persistenet Database ที่เก็บอยู่ใน Memory มีจริงๆ ครับ ลองไปดูที่ bambo เป็น Open Source ตัวนี้คุยว่าเร็วกว่า Oracle 9000 เท่า ไม่แปลกเลยครับ ก็ทุกอย่างมันอยู่ใน Memory อยู่แล้ว แถมไฟดับแล้วข้อมูลไม่หายอีกต่างหาก ทำได้อย่างไรลองศึกษาไปดูเองครับ มันเหมาะกับ Web Application มากครับ ตัวนี้ Port มาจาก ภาษา Java ที่ชื่อว่า Prevalance ซึ่งเพิ่งได้รับรางวัล Jolt ของปีนี้เลยครับ ถ้าสนใจลอง email มาครับ ผมอาจจะเอามาเขียนให้อ่านกัน

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

Customer c = new Customer();
c.name = "ABC Co., Ltd.";
PersistentEngine.save(c);

    ง่ายๆ เพียงแค่นี้เองครับ คุณทำงานเหมือนปกติ สร้าง Object ขึ้นมา เอาของใส่ให้เรียบร้อย จากนั้นก็เรียกคำสั่งที่เครื่องมือทำ Persistence จัดเตรียมไว้ให้ เพื่อบันทึก Object ของคุณให้กลายเป็น Persistence Object จากนั้นต่อให้คุณปิดเครื่องมันก็ไม่หายแล้วครับ ถ้าคุณเปิดเครื่องใหม่ (ไม่จำเป็นต้องเป็นเครื่องเดิม) คุณสามารถเรียกใช้ Object ที่ต้องการได้โดย

Customer c =(Customer)PersistentEngine.LoadByPrimaryKey("ABC Co., Ltd.");

    ต้องบอกก่อนนะครับนี่คือเรื่องสมมติ มันแล้วแต่ว่าเครื่องมือ Persistence แต่ละตัวใช้คำสั่งไม่เหมือนกัน แต่คิดว่าส่วนมากก็จะทำนองนี้ครับ

Object-Oriented Database

    เรามาพูดถึงการเก็บข้อมูลในฐานข้อมูลกันบ้าง จะเห็นว่า การเก็บข้อมูลของ Object นั้นใช้หลักการ Persistance ในการเก็บ ปัญหาก็คือทาง back-end แล้วจะเก็บอย่างไร จะเก็บโดยใช้ Relational Database ก็มีปัญหาเยอะมาก ก็เลยมีคนคิดค้น DBMS แบบใหม่คือ Object-Oriented Database ซึ่งช่วยให้การเก็บข้อมูลเป็นไปอย่างธรรมชาติ สอดคล้องกับแนวคิดของ Object-Oriented  แถมยังต้องสามารถรองรับ Interface, Inheritance หรือแม้แต่ค้นหาแบบ Adhoc ทั้งนี้ก็ขึ้นกับความสามารถของแต่ละเจ้าครับ

    จุดอ่อนของ Object-Oriented Database ก็คือ ทุกวันนี้ยังหามาตรฐานอะไรไม่ได้ เข้าทำนองต่างคนต่างทำ วิธีใช้ หรือความสามารถต่างๆ นั้น ก็มีความแตกต่างกันค่อนข้างสูง  มีผู้ใช้ไม่มากนัก คนที่จะเริ่มนำไปใช้ก็ลังเลครับ ไม่มีคนนำหน้าไปก่อน กลัวเดินไปแล้วพลาดตกท่อ ไหนเลยเรื่องความสามารถ เรื่องการ Support ของบริษัท ตลอดจนความเสถียรของระบบ เหล่านี้ล้วนแล้วแต่สร้างทำให้ผู้ใช้ไม่ค่อยกล้าใช้ ผมเองก็ไม่ค่อยมีความรู้เรื่องนี้มากนัก เลยขอข้ามไปครับ

Mapping is for Mapping between Object-Oriented and Relational Database

     ถ้า Object-Oriented Database มันไม่น่าเชื่อถือ ทำไมเราไม่กลับไปหาเพื่อนเก่าของเราที่อยู่เคียงข้างกันมากว่า 30 ปี เขาแกร่ง เขาน่าเชื่อถือ เขาผ่านร้อนผ่านหนาวมาเยอะ นั่นก็คือ Relational Database นั่นเอง ในตอนหน้า ผมจะมาคุยให้ฟังว่า เราจะเอา Object-Oriented มาเป็นเกลอกับ Relational Database ได้อย่างไร

ยังไม่จบครับ ขอต่อเร็วๆ นี้