Thursday, August 24, 2006

Amazon EC2

Amazon EC2 เป็นบริการใหม่ของ Amazon
ทำให้เราสามารถ สร้าง Amazon Machine Image (AMI) ที่ต้องการ
(จริงๆแล้ว มันก็คือ disk image ที่เอาไปใช้ run virtual machine)
นำไป deploy บน Amazon EC2
จากนั้นก็สามารถ start instance ตามจำนวนที่ต้องการได้

ลองดูตัวอย่างสถานะการณ์การใช้งาน
Mary wishes to deploy her public, fault tolerant, three tier web service in Amazon EC2. Her grand plan is to have her web tier start off executing in seven instances of ami-fba54092, her application tier executing in twenty instances of ami-e3a5408a, and her multi-master database in two instances of ami-f1a54098.


ค่าบริการคิดตามที่ใช้จริง
processing - $0.10 per instance-hour
data transfer (internet traffic) - $0.20 per GB
Storage - $0.15 per GB
(storage ใช้บริการจาก Amazon S3)

วิธีที่สร้าง AMI (Amazon Machine Image) ก็คล้ายๆกับที่เรา add guest-os ให้กับ xen
โดยต้องทำในเครื่องเราให้เรียบร้อยก่อน
จากนั้นจึง upload ขึ้นไป

ดูจากวิธีการสร้าง image แล้ว
ตัว infrastructure ของ EC คงใช้ fedora กับ xen

ข้อจำกัดอีกอย่างก็คือ
ตัว server ต้องใช้ dynamic IP เท่านั้น

ข้อดีที่เห็นชัดๆ ก็คือ เราสามารถเพิ่ม instance ได้ตามต้องการ
ทำให้การตอบสนองต่อพวก spike load ทำได้โดยง่าย

อย่างนี้ A-NET, O-NET ก็น่าไปใช้บริการนะ
เพราะปีหนึ่งมีประกาศผลแค่ไม่กี่ครั้ง แต่ต้องลงทุน server ไปกับ spike load

Related link from Roti

Functional test with Selenium RC

ลองใช้ Selenium มาทั้ง 3 แบบแล้ว
core, firefox extension, remote-control
สุดท้ายก็ชอบแบบ remote-control มากที่สุด
โดยเฉพาะการใช้ร่วมกับ ruby

ภาพรวมการทำงานของ Selenium remote-control ก็คือ
เราจะ start selenium server ขึ้นมาตัวหนึ่ง
เวลาจะ test เราก็จะเขียน program เพื่อส่ง command ที่ต้องการ test
ไปยัง server, โดย server จะสื่อสารและสั่งงานให้ browser ทำตาม command ที่เราสั่ง



ที่นี้ลองมาดูการทำงานภายในของ Selenium ดูบ้าง
วิธีการที่ selenium ใช้ควบคุม browser ก็คือการใช้ javascript
เช่นสมมติว่าเราต้องการให้เกิดการ click ที่ปุ่มๆหนึ่ง

<a href="xxxx" id="myButton">click me</a>

ในแง่ของ test script เราก็จะส่งคำสั่งต่อไปนี้

cmd = "click"
param1 = "id=myButton"

ทีนี้ selenium จะทำอย่างไร ปุ่มนี้จึงจะ click ได้
ขั้นที่ 1 ก็คือหา element ที่ต้องการ click ให้เจอก่อน
โดยวิธีการหา จะขึ้นอยู่กับ prefix ที่เรากำหนดไปใน parameter
เช่นถ้ากำหนด id= นำหน้า, selenium ก็จะใช้วิธี getElementById
แต่ถ้าเป็นพวก xpath=//img[@alt='The image alt text'] ก็จะใช้ xpath
หรือถ้านำหน้าด้วย css= ก็จะใช้ css selector ในการหา

ขั้นที่ 2 ก็คือเมื่อเจอ element ที่ต้องการแล้ว ก็ต้องทำให้เกิดการ click ขึ้นมา
ลองดูตัวอย่างของการ simulate mouse click ใน Firefox ดู
MozillaPageBot.prototype.clickElement = function(element, clientX, clientY) {

triggerEvent(element, 'focus', false);

// Add an event listener that detects if the default action has been prevented.
// (This is caused by a javascript onclick handler returning false)
var preventDefault = false;

...

// Trigger the click event.
triggerMouseEvent(element, 'click', true, clientX, clientY);

...

if (this.windowClosed()) {
return;
}

triggerEvent(element, 'blur', false);
};

จะเห็นว่า มันทำการ simulate event focus จากนั้นก็ทำการสร้าง event mouse click
สุดท้ายก็ส่ง event blur
ส่วนการทำงานภายในของ function triggerMouseEvent
ถ้าเป็น mozilla ดูเหมือนจะใช้วิธีนี้
var evt = document.createEvent('MouseEvents');
.. // init event
element.dispatchEvent(evt);

จะเห็นได้ว่า วิธีการทำงานนั้นน่าสนใจทีเดียว

ประเด็นที่ตามมาของการใช้ javascript control ก็คือ
javascript นั้นจะ run ใน domain name ที่เราต้องการ test อย่างไร
เนื่องจาก javascript จะทำงานได้กับ domain name ที่เรา load javascript นั้นมาเท่ากัน
Selenium เลยใช้วิธีการ start proxy server ขึ้นมา
เพื่อบังคับให้ request ของ browser วิ่งผ่านมันก่อน
เพื่อที่มันจะได้ inject javascript ที่ต้องการลงไปได้



หันไปดูด้านผู้ใช้ดูบ้าง
ลองดูตัวอย่าง ruby code ที่ผมเขียน test

def setup
@domain = 'http://wcfweb.test:8080'
@sel = Selenium::SeleneseInterpreter.new("selenium.server.test", 4444,
"*firefox", @domain, 15000)
@sel.start
@home = "#{@domain}/fin/app?page=wcf2000/Wcf2110_1&service=page"
end

def submit_cheque(no, date, bank, amount)
to_page2
@sel.click("link=0.00")
type_cheque(no, date, bank, amount)
calc_charge
@sel.click("save_btn")
@sel.wait_for_page_to_load(15000)
end

def t_cheque_amount_entry_but_no_other_info
submit_cheque("", "", "", 2000)
assert(@sel.is_text_present("กรุณาระบุเลขที่เช็ค"))
assert(@sel.is_text_present("กรุณาระบุวันที่เช็ค"))
assert(@sel.is_text_present("กรุณาระบุรหัสธนาคาร"))
end

def t_cheque_entry_wrong_date
submit_cheque("1234567", nextDay(2), "", 2000)
assert(@sel.is_text_present("วันที่เช็ครับลงล่วงหน้ามากกว่า 1 วัน"))
end

def t_cheque_entry_wrong_bank_code
submit_cheque("1234567", nextDay(1), 1234, 2000)
assert(! @sel.is_text_present("วันที่เช็ครับลงล่วงหน้ามากกว่า 1 วัน"))
assert(@sel.is_text_present("รหัสธนาคารไม่ถูกต้อง"))
end


เวลา run, Selenium ก็จะเปิด browser ทำงาน
โดย browser มีหน้าตาแบบนี้

Related link from Roti

Wednesday, August 23, 2006

Dojo Render Time

ช่วงแรกๆที่ใช้ Dojo จะยังไม่เจอปัญหาเรื่อง Render Time.
แต่พอในหน้าจอเริ่มมี element มากขึ้น
เวลาที่ใช้ในการ render หน้าจอ จะเริ่มช้าลงอย่างเห็นได้ชัด

ปัญหาก็คือ
เวลาเราใช้ dojo เรามักจะใช้ในรูปแบบนี้
<span dojoType="tooltip" 
connectId="entryField"
caption="xxxxxx"/>

ประเด็นก็คือ แล้ว dojo จะรู้ได้ไงว่าต้องเปลี่ยน dom element นี้ให้เป็น dojo component
Dojo ก็เลยต้อง scan document ทั้งอัน เพื่อที่จะหาว่ามี attribute dojotype อยู่ที่ไหนบ้าง
ยิ่งหน้าจอเรามี dom element เยอะขึ้นเท่าไร ก็ยิ่งเสียเวลามากขึ้นเท่านั้น

การแก้ไขก็คือ จำกัดวงไม่ให้ dojo ต้อง scan เอกสารทั้งหมด
เริ่มด้วยการ set djconfig
<script> 
djConfig = {
..
parseWidgets: false,
searchIds: [],
..
};
</script>

จากนั้นในแต่ละ element ที่ต้องการให้เป็น dojo component
ก็ให้ใส่ script นี้ลงไป
<span dojoType="tooltip" 
connectId="entryField"
caption="xxxxxx"
id="this_is_my_dojo"/>
<script>djConfig.searchIds.push("this_is_my_dojo");</script>

Related link from Roti

Label กับ Form

Label Placement in Forms
บทความนี้เขา track ลูกตา กับ form ที่ align ในแบบต่างๆ
แล้วสรุปให้เราดูว่า ข้อดีข้อเสียเป็นอย่างไร

Related link from Roti

Monday, August 21, 2006

Closures for Java

มี proposol แบบนี้ออกมา ค่อยรู้สึกมีความหวังกับภาษานี้หน่อย
(หลังจากปล่อยให้ C# นำหน้าไปนาน)

ดูตัวอย่างแรกสุดก่อน
public static void main(String[] args) { 
int plus2(int x) { return x+2; }
int(int) plus2b = plus2;
System.out.println(plus2b(2));
}

ในที่สุด Kingdom of Nouns อย่าง java ก็มี verb citizen โผล่เข้ามาแล้ว
ในบรรทัดแรก plus2 ก็คือ Type ชนิด function
ส่วนบรรทัดที่ 2 ก็คือการกำหนดให้ plus2b เป็นตัวแปรที่ reference ไปยัง function plus2

บรรทัดที่ 1 และ 2 จากตัวอย่างข้างบน สามารถยุบเขียนในรูป anonymous function ได้แบบนี้
int(int) plus2b = (int x) {return x+2; };


แถมด้วย syntactic sugar
แทนที่จะต้องเขียนแบบนี้
void sayHello(java.util.concurrent.Executor ex) { 
ex.execute((){ System.out.println("hello"); });
}

ก็สามารถเขียนแบบนี้ได้
void sayHello(java.util.concurrent.Executor ex) { 
ex.execute { System.out.println("hello"); }
}

Related link from Roti

Sunday, August 20, 2006

Emacs & xft

ตั้งแต่ใช้ Emacs มา มีเรื่องขัดใจอยู่อย่างเดียว
ก็คือ text ของ emacs ใน linux มันไม่เป็น anti-aliased
วันนี้ก็ลอง build emacs จาก branch ที่เขา implement feature xft ดู

ขั้นตอนก็คือ
checkout จาก trunk ก่อน

cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/cvsroot/emacs co emacs

จากนั้นก็สั่ง update จาก branch

cd emacs
cvs up -Pd -r XFT_JHD_BRANCH

สั่ง configure
(ตรงนี้ distro แต่ละ distro คงไม่เหมือนกันนะ
ถ้าดูเอกสารที่คุณ poonlap แนะนำ จะไม่ต้องมี --x-includes กับ --x-libraries
กรณีของผมเป็น fedora core 5, ถ้าไม่มีจะ compile ไม่ผ่าน)

./configure --with-xft --with-gtk --x-includes=/usr/include/X11 --x-libraries=/usr/lib/X11

จากนั้นก็สั่ง

make bootstrap
make install


เท่านี้ก็ได้ emacs ฉบับสวยงาม
แต่ข้อเสียก็คือ มันแสดงภาษาไทยไม่ได้
เศร้า
(poonlap, ถ้าอ่านเจอ ก็ช่วยหาทางแก้ให้หน่อยนะ)

เครื่องผมก็เลยมี emacs มัน 2 แบบเลย
ถ้าดู code ภาษาอังกฤษก็ใช้ build with xft
ถ้าภาษาไทย ก็ใช้แบบธรรมดาไป

Update: มีปัญหา Segment fault เกิดขึ้นบ่อยมาก
ถ้า switch ไปใช้ workspace อื่น

Related link from Roti