Saturday, April 21, 2007

ตัวอย่าง aspect อย่างง่าย

ในโพสต์นี้ผมแนะนำตัวอย่าง aspect ที่น่าจะเข้าใจได้ไม่ยากนักสำหรับการเริ่มต้นหัดเขียน AOP
โจทย์คือ "สร้าง aspect สำหรับจับเวลาให้เมธอดในคลาส Target" ครับ

1. ให้สร้่าง aspect เป็นชื่อ TimeMeasurement ตั้ง package เป็นอะไรก็ได้ เช่น net.ckblog.aspect.TimeMeasurement จะได้ไฟล์ชื่อ TimeMeasurement.aj ซึ่งจะคอมไพล์ได้ด้วยตัวคอมไพเลอร์ของ AspectJ
2. ให้สร้างคลาส ชื่อ Target อาจจะเป็น net.ckblog.Target แล้วให้มี 2 เมธอด ชื่อ compute1000() กับ compute2000() แล้วลองเขียนโค้ดให้วนรอบใน 2 เมธอดนั้น 1000 รอบ และ 2000 รอบ ตามลำดับ
จากนั้นให้เตรียมคลาส Main เพื่อสร้าง object ของ Target แล้วทำการเรียกใช้ทั้งสองเมธอดดังกล่างใน main()
3. กลับมาที่ aspect TimeMeasurement ให้ประกาศ pointcut โดยเราจะใช้ pointcut designator (PCD) ชื่อ execution() ในการเลือก join point 2 จุด ณ ตำแหน่งการทำงานของเมธอด ของ compute1000() และ compute2000()
ซึ่งเหตุผลในการใช้ PCD มาจากวิธีคิดแบบนี้ครับ
- การทำงานของเมธอด คือ execution of method (ต่างจากการเรียกใช้ คือ call)
- นั่นคือความหมายของ PCD ชื่อ execution(...) (ถ้าเป็นการเรียกใช้ก็จะเป็น PCD ชื่อ call())
และเป้าหมายของเราคือเมธอด compute1000() และ compute2000
จะได้ pointcut ดังต่อไปนี้

execution(public Target.compute1000()) ||
execution(public Target.compute2000())

ความหมายคือ เราสร้าง pointcut จาก PCD มากกว่า 1 ตัว และในกรณีนี้ เราใช้ PCD 2 ตัวทำการ or กัน
ในการใช้งานจริง จะสามารถยุบรวมให้เป็น PCD เดียวโดยใช้ wildcard ซึ่งจะเป็นตามโค้ดต่อไปนี้ครับ

execution(public Target.compute*())

(หมายเหตุ: pointcut นี้จะเลือกทุก ๆเมธอดของคลาส Target ที่ชื่อเมธอด ขึ้นต้นด้วย compute นะครับ
นั่นคือถ้าเีราเพิ่ม compute3000() เข้าไป method ใหม่ก็จะโดนเลือกด้วย ซึ่งจะทำให้ความหมายไม่ตรงเป๊ะ ๆ กับ code แรก
แต่ผมต้องการแสดงให้เห็นว่าเราสามารถเลือกเชิงประมาณโดยใช้ wildcard ได้)

4. ต่อมาเราก็จะประกาศ advice เพื่อให้ทำงาน ณ ตำแหน่ง join point ที่เราเลือกมาด้วย pointcut ในข้อ 3 ครับ
ก่อนจะไปต่อ ผมเล่าให้ฟังนิดนึงว่า join point มีสมบัติสำคัญ ๆ คือ
1) เราเข้ามาที่จุด join point ได้
2) เมื่อมาถึงแล้ว เราทำงานที่จุด join point ได้
3) และเมื่อมาถึงแล้ว เราออกจากจุด join point ได้

ซึ่ง advice ก็คือคำแนะนำที่เราบอกกับโปรแกรมว่าควรจะทำอะไรที่จุด join point นี้

ตาม aspect เราตั้งใจว่าจะ "จับเวลา" การทำงานของ 2 method
นั้นคือเราะจะมีการจับเวลา "ก่อน" และ "หลัง" ในแต่ละ join point ที่เลือกไว้ด้วย pointcut ในข้อ 3 ครับ
ตรงนี้เราจะใช้ before() เพื่อนิยามการแนะนำขณะเข้า join point
และ after() เพื่อนิยามการแนะนำขณะออกจาก join point
ดังนั้นเราก็จะได้

before(): <ชื่อ pointcut>() {
// จับเวลาใส่ตัวแปร
}

after(): <ชื่อ pointcut>() {
// จับเวลา แล้วเอาไปลบกับตัวแปรที่ตั้งค่าไว้ในโค้ดของ before
// แล้ว System.out.println(เวลา);
}


แล้วก็สั่งรันโปรแกรม ก็เป็นอันเสร็จพิธีครับ

ในตัวอย่างที่ผมยกมาให้ดูนี้ ผมใช้ join point model แบบ pointcut-advice เพื่่ออธิบาย aspect สำหรับ"จับเวลา" โดยสร้าง pointcut จากการใช้ PCD 2 ชุดมา or กัน เพื่อเลือก (quantify) join point 2 ตำแหน่งใน class Target แล้วก็สร้าง advice เพื่อแนะนำให้โปรแกรมทำการจับเวลา "ก่อน" และ "หลัง" จุดที่เลือกมาด้วย pointcut ผมตั้งใจละ code ไว้ให้ผู้อ่านลองนำไปเขียนเพิ่มเติมเองนะครับ

สำหรับ join point อีก model ที่มีใน AspectJ คือ inter-type declaration หรือเรียกว่า introduction จะกล่าวถึงในโพสต์อื่น ๆ ครับ

หมายเหตู ผมโพสต์ตอบแบบเดียวกันนี้ไว้ในกระดานข่าวของ narisa.com กระทู้นี้ครับ

เหตุผลที่ AOP แตกต่างจาก MOP

ผมกำลังสร้างระบบย่อยเชิงลักษณะ (AOP subsystem) สำหรับ Groovy โดยอิมพลีเม้นต์บน Meta Object Protocol (MOP - ระเบียบการเหนือวัตถุ?) ให้สนับสนุนสมบัติหลัก 2 ประการของแบบจำลอง pointcut-advice นั่นคือ การเลือกเชิงปริมาณ (Quantification) และ การไม่รับรู้ (Obliviousness)

โดยปกติ การใช้เมต้าคลาสใน Groovy ก็สนับสนุนการไม่รับรู้ของวัตถุเป้าหมายได้อยู่แล้วเนื่องจากระเบียบการเหนือวัตถุจะใช้เมต้าคลาสของแต่ละวัตถุในการเรียกใช้เมธอดและเข้าถึงสมบัติของวัตถุนั้น ๆ
สิ่งที่ขาดไปก็คือการเลือกเชิงปริมาณ ที่ใน AspectJ ใช้ wildcard เพื่อเลือกหลาย ๆ joinpoint จาก ประโยค pointcut เพียง 1 ประโยค
รวมถึงจุดเล็ก ๆ น้อย ๆ ในการอิมพลีเม้นต์ที่ยอมให้พฤติกรรมซับซ้อนเช่น proceed หลายระดับใน advice แบบ around ทำได้ง่ายขึ้น
และนี่คือจุดสำคัญที่ AOP แตกต่างจาก MOP และเป็นเหตุผลว่าทำไม AOP ถึงยังจำเป็นแม้จะมี MOP อยู่แล้วในภาษาพลวัตร

Sunday, April 15, 2007

Groovy และเมต้าคลาสที่สนับสนุน AOP

ผมบล้อกเกี่ยวกับการอิมพลีเม้นต์เมต้าคลาสใน Groovy เพื่อสนับสนุนการโปรแกรมเชิงลักษณะตามโมเดลของ AspectJ โค้ดที่โพสต์ไว้ส่วนใหญ่มากจากบทความของ John McClean บน InfoQ ที่เพิ่งไปอ่านเจอมา ตกใจเล็กน้อยที่เค้าเขียนไว้นานแล้ว แต่ก็ดีใจที่เจอ เพราะผมยังห่างไกลเรื่องแนวคิดทาง Meta Object Protocol (MOP) อยู่มาก เห็นการเอาทั้ง 2 แนวคิด (คือ AOP และ MOP) มารวมกันทำให้ผมเข้าใจมันมากขึ้นและทำให้งานวิจัยค่อนข้างก้าวกระโดดทีเดียว



จากบทความที่ว่า ผมเห็นชัดเจนมากขึ้นว่าทำไมคนในโลกภาษาพลวัตรทั้งหลายเฉย ๆ กับ AOP เพราะ advice พื้นฐานของ AOP จำพวก before, after, around กลายเป็นของง่าย ๆ ด้วยเมต้าคลาส แต่จุดหนึ่งที่น่าสนใจคือ สมบัติของ AOP ในการเลือกเชิงปริมาณ (Quantification) นั้นยังทำได้ยากในแบบ crosscutting แต่ง่่ายในแบบ hierarchy ด้วยเมต้าคลาส แต่ยังไงก็ง่ายกว่าภาษาเชิงวัตถุแบบสถิตย์อย่าง Java (เมื่อไม่ใช้อะไรที่เกี่ยวข้องกับ AOP เลย) อยู่ดี

Thursday, April 12, 2007

การโปรแกรมเขิงลักษณะในอีก 10 ปี

Panelists จากการประชุมวิชาการ AOSD 07 พูดเสนอมุมมองที่น่าสนใจหลาย ๆ อย่างเกี่ยวกับ AOP ในอีก 10 ปีข้างหน้าว่าจะมีรูปแบบอย่างไร ผมเลยสรุปและรวมเข้ากันกับแนวคิดที่เสนอโดย Keynote Speakers 2 คนจาก AOSD 07 เช่นกันครับ งานวิจัยของผมมีหลาย ๆ ส่วนที่เป็นไปในแนวทางที่ทั้ง Panelists และ Keynote เสนอมา ผมเลยจะแทรกความเห็นของผมลงไปด้วยนะครับ



Crosscutting Concerns ไม่จำเป็นต้องตัดขวางเฉพาะการไหลของโปรแกรม - ประเด็นนี้ค่อนข้างตรงใจผมครับ เนื่องจากงานวิจัยใกล้เคียงกับที่ผมทำอยู่ ก็สามารถอธิบายได้ด้วย AOP และมันก็ไม่ใช่การไหลของโปรแกรมเสียทีเดียว ซึ่งจุดนี้ยืนยันแนวคิดการใช้งาน AOP ในโลกของ High-Performance Computing ได้ค่อนข้างดีครับ



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



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



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