Saturday, April 29, 2006

จาก Signal vs. Noise - It's all the same
Question
“how do you find time to do PR or marketing when you are building your products?”

Answer

Here’s the secret: it’s all the same thing.
...
Building and improving Rails is PR. Designing great interfaces is marketing. Providing quick customer support is advertising.

Related link from Roti

Friday, April 28, 2006

Auto Test with Rails

คิดว่าจะ run continuous test มานานแล้ว
เพราะเครื่องที่บ้านมันมี cpu เหลืออยู่ 1 ตัว
แต่จนแล้วจนรอด ก็ไม่ได้ทำสักที
(สาเหตุอีกสาเหตุหนึ่งอาจจะเป็นเพราะ ช่วงนี้ไม่ได้ทำ project อะไร
เป็นชิ้นเป็นอัน ก็เลยไม่มี test ที่ต้องคอย keep track ยาวๆ)

วันนี้อ่าน nuby on rails เจอว่าใน Rails สามารถทำ continuous ได้เหมือนกัน
โดยใช้ tool ที่ชื่อ ZenTest
ดู screen cast ของการใช้ autotest ได้ที่นี่
Movie of autotest in action

Related link from Roti

IE Bug ใน XMLHttpRequest

วันนี้นั่งทดสอบ Application บน Browser ทั้ง 3 ตัว
โดยจับเอาจอมาวางเรียงกัน 3 จอ
IE, Firefox, Safari

สนุกดี ที่ได้เห็นจุดเล็กจุดน้อยต่างๆกันไป
อย่าง image link บน firefox กับ IE
แสดงสีเป็นปกติ แต่บน Safari แสดงสีเพี้ยนไป
ซึ่งจับได้ว่าเป็นเพราะตอน export image จาก photoshop
มีการ set flag color profile ไว้
ทำให้สีบน safari เพี้ยนไป

แต่ที่หนักสุด ก็คือ Feature Ajax
ที่ไม่ทำงานบน IE
พยายามใส่ message เพื่อตรวจว่ามันตายตรงไหน
ปรากฎว่ามันไปตายตอนที่
เราเรียกใช้ response.responseText
หลังจาก search หาบน google อยู่พักใหญ่
ก็พบว่าเป็น bug ของ IE
ซึ่งเกิดในกรณีที่ message ที่ส่งกลับมา มี Content-Type
ที่ระบุ encoding มาด้วย, การเรียกใช้ responseText
จะทำให้ IE หยุดทำงาน
สาเหตุที่เป็นเช่นนี้เพราะ IE ตั้ง assumption ว่า message ที่ส่งกลับมา
จะมี encoding ในรูปของ utf8 พอมันเจอ header ที่ระบุ
encoding มา ก็เลยเลิกทำงานไปเสียเฉยๆ

Content-type ที่มีปัญหา
Content-Type: text/plain; charset=tis620

Content-type ที่​ IE ชอบ
Content-Type: text/plain


เบื่อจริงๆ เมื่อไรคนจะเลิกใช้ IE กันเสียที

Related link from Roti

Wednesday, April 26, 2006

[Script.aculo.us] Customize Effect

Script.aculo.us คือ javascript library
ที่ช่วยในการ ทำ Effect ต่างๆ
เช่น Fade, SlideDown, Highlight, ...

ช่่วงนี้ ผมอยู่ระหว่าง design UI ของโปรเจคใหม่อยู่
มี effect บางอย่างที่ผมต้องการ แต่ไม่มีอยู่ใน library ของ Script.aculo.us
ก็เลยต้องหาวิธีว่าจะ implement Effect ได้ง่ายๆได้อย่างไร
โชคดีที่ตัว library ของ Script.aculo.us ออกแบบมาดี
ทำให้เราสามารถ extend class เพือสร้าง customize effect ของเราได้

ตัวอย่างที่จะทำให้ดู ก็คือ Effect ที่ทำการ slide ในแนวนอน
ยกตัวอย่าง use case การใช้ ก็อย่างเช่น
ช่วยให้ web application เรามี navigation ด้านข้างที่สามารถเลื่อนแสดงหรือซ่อนได้



โดยผมกำหนด style sheet ของ sidebar และ content ดังนี้
#sidebar {
width: 20%;
height: 100%;
background-color: #ccc;
float: left;
}

#content {
display:block;
width: 99%;
float:right;
}


เริ่มเขียน Effect โดยการ สร้าง class ขึ้นมาก่อน
Effect.BarSlide = Class.create();

จากนั้นก็สั่ง extend จาก class Effect.Base
(javascript ที่เขียนนี้ จะยึด pattern ตามที่ Prototype.js
วาง pattern ไว้)
Effect.BarSlide = Class.create();
Object.extend(Object.extend(Effect.BarSlide.prototype, Effect.Base.prototype), {
// method (function) go here..
});

function หลักๆที่เราต้อง implement มีอยู่แค่ 2 function
คือ initialize กับ update
  • function initlialize ทำหน้าที่เป็น constructor ของ class เรา
    โดยกำหนดให้ pass ค่า Object ID ของ content กับ sidebar เข้ามา
    รวมทั้งขนาดของ sidebar (ระบุเป็น % ของขนาดหน้าจอ)
      initialize: function(left, right, percent) {
    var options = arguments[3] || {};
    this.left = left;
    this.right = right;
    this.percent = percent;
    this.start(options);
    },

    บรรทัดสุดท้ายเป็นบรรทัดที่สั่งให้ effect เริ่มทำงาน
    ส่วน arguments[3] คือ optional argument เช่น
    ช่วงเวลาที่ใช้เลื่อน
  • function update
    function นี้จะถูกเรียกใช้ตามจำนวน FPS (frame per second) * ช่วงเวลา (duration) ที่กำหนด
    โดยเรามีหน้าที่ render ว่า frame ณ จุดนั้นๆ มีหน้าตาเป็นอย่างไร
    ค่า parameter position ที่ pass เข้ามา จะอยู่ในช่วง 0 ถึง 1
      update: function(position) {
    var value = this.percent * position;
    $(this.left).style.width = value + "%";
    $(this.right).style.width = (100 - value) + "%";
    $(this.left).style.display = 'block';
    }
    จะเห็นว่าผมแค่สั่งเพ่ิมความกว้างของ slidebar กับ ลดความกว้างของตัว content ไปเรื่อยๆ
    โดยคิดเป็นอัตราส่วนตาม position ที่ pass เข้ามา


การนำไปใช้งาน ก็แค่สั่ง
function show() {
new Effect.BarSlide('sidebar','content',20, {duration:0.5});
}

Related link from Roti

Use case ของการใช้ Rails

ตอนนี้ผมได้ use case ของการใช้ Rails อีกแบบหนึ่งแล้ว
นั่นก็คือการใช้ rails ทำ prototype
เพราะข้อดีของ Rails ก็คือ มันพ่นออกมาได้เร็ว
ส่วน production ของจริง, ยังใช้ tapestry เหมือนเดิมอยู่
(ใช้ rails ไม่ได้ เพราะติดเงื่อนไข ว่า
rails ยังไม่ support ตัว Database ที่ใช้อยู่)

ผลพวงอีกอย่างที่ได้จาก prototype ด้วย rails ก็ืคือ
มันทำให้เกิด insight ท่ีทำให้มองได้ชัดขึ้นว่า
component ของ tapestry ใน production
ควรจะออกแบบอย่างไรดี

Related link from Roti

Monday, April 24, 2006

Java Byte Code

เมื่อวันเสาร์ไปประชุมบริษัทฯมา เลยได้รับทราบข่าวว่า
มีลูกค้ารายหนึ่งอยากให้ลอง compile java ใหม่บนเครื่อง Target แทนที่
จะ compile มาจากเครื่อง develop แล้วค่อยเอามาวางบน Target
เหตุผล แค่ เผื่อจะแก้ปัญหาได้
ซึ่งปัจจุบันปัญหาที่หลงเหลือ ก็มีเรื่อง Out of Memory
ซึ่งทาง IBM ที่ australia แนะนำมาแล้วว่่าเกิดขึ้นทีส่วน native
กับ ปัญหา jre ตาย แบบ exception fault
ซึ่ง random เกิด 3-4 เดือนครั้ง

เริ่มสงสัยว่าเป็น idea ใครนี่, อาจารย์ที่ปรึกษา หรือ IBM หรือ บริษัทที่ดูแล mainframe, หรือจากลูกค้าเอง
โดยหลักการแล้ว ผมว่า byte code ที่เกิดจาก platform คนละอัน มันไม่น่าจะทำให้
เกิด exception fault หรือ out of memory ได้นะ

ว่าแล้ว ก็อยากรู้ว่า byte code หน้าตามันเหมือนหรือต่างกันแค่ไหน
ก็เลยลอง compile เปรียบเทียบระหว่าง IBM jdk1.3, Sun jdk1.4 ดู

ลองแบบง่ายๆก่อน
public class HelloWorld {
private String name;

public HelloWorld(String name) {
this.name = name;
}

public String toString() {
return "Hello " + name;
}
}

ผลลัพท์ก็คือ หน้าตา byte code ที่ได้ เหมือนกันเพี๊ยะ ยกเว้นเลข version ที่ส่วน header
// class version 45.3 (196653)
// access flags 33
public class HelloWorld {

// compiled from: HelloWorld.java

// access flags 2
private Ljava/lang/String; name

// access flags 1
public (Ljava/lang/String;)V
L0 (0)
LINENUMBER 5 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.()V
L1 (3)
LINENUMBER 6 L1
ALOAD 0
ALOAD 1
PUTFIELD HelloWorld.name : Ljava/lang/String;
L2 (7)
LINENUMBER 7 L2
RETURN
L3 (9)
LOCALVARIABLE this LHelloWorld; L0 L3 0
LOCALVARIABLE name Ljava/lang/String; L0 L3 1
MAXSTACK = 2
MAXLOCALS = 2

// access flags 1
public toString()Ljava/lang/String;
L0 (0)
LINENUMBER 10 L0
NEW java/lang/StringBuffer
DUP
LDC "Hello "
INVOKESPECIAL java/lang/StringBuffer.(Ljava/lang/String;)V
ALOAD 0
GETFIELD HelloWorld.name : Ljava/lang/String;
INVOKEVIRTUAL java/lang/StringBuffer.append(Ljava/lang/String;)Ljava/lang/StringBuffer;
INVOKEVIRTUAL java/lang/StringBuffer.toString()Ljava/lang/String;
ARETURN
L1 (10)
LOCALVARIABLE this LHelloWorld; L0 L1 0
MAXSTACK = 3
MAXLOCALS = 1
}

เพื่อความแน่ใจ ก็เอา class file ไป compare แบบ binary diff อีกที
ซึ่งผลที่ได้ก็เหมือนกันคือ ต่างกันแค่ byte ที่ 6 กับ 8 เท่านั้น (ส่วน header)

ทดลอง class ที่ซับซ้อนมากขึ้นอีกนิดหนึ่ง ก็คือ Algorithm Shear sort
ผลที่ได้ก็เช่นเดียวกัน ต่างกันแค่ตรงเลข version number

แต่ถ้าลองเอา jdk1.5 มา compile ดู ,คราวนี้สิ เกิดความแตกต่างแน่นอน
อย่าง StringBuffer ก็จะกลายเป็น StringBuilder

Note: ใครที่เคยผ่านหูผ่านตา forum ที่พูดถึงกรณี recompile ก็ช่วยแนะนำด้วยครับ

Related link from Roti

JDBC 4.0 Query Interface

เห็นแล้วต้องรีบแจ้งข่าว
binkley 's BLOG ลงเรื่อง Nifty JDBC 4.0
ลองดูตัวอย่าง code เขา
เขาใช้วิธีนี้ในการ insert ข้อมูลลง table
final BobQuery query = connection.createQueryObject(BobQuery.class);
query.addBob("Your Name Here.");

ดูเหมือนจะไม่มีอะไร ก็แค่ไปเรียก Query Object มาตัว แล้วก็เรียกใช้
method addBob
แต่จริงๆแล้ว Magic อยู่ที่ BobQuery ซึ่งประกาศเป็น interface ดังนี้
public interface BobQuery
extends BaseQuery {
@Update(sql = "INSERT INTO BOB(name) VALUES(?1)",
keys = RETURNED_KEYS_DRIVER_DEFINED)
DataSet addBob(final String name);

@Select("SELECT * FROM BOB WHERE name = ?1")
DataSet findBobByName(final String name);

@Select("SELECT * FROM BOB")
DataSet findAllBobs();

@Update("DELETE FROM BOB")
int removeAllBobs();
}

ว้าว ดูดี
ยังไม่หมด ทายสิว่า method findBobByName return อะไร
ถ้าดูใน interface มัน return DataSet
แต่ถ้าดูใน code เราสามารถ get Object จาก dataset ได้เลย
public class Bob {
public BigDecimal id;
public String name;
}
...

final Bob bob = query.findBobByName(name).get(0);

ดูจาก code ที่ binkley มันแปลกๆอยู่ตรง การ define interface
จากที่เขาเขียน
DataSet findBobByName(final String name);

จริงๆแล้ว มันน่าจะเขียนแบบนี้ มากกว่านั้น
DataSet<Bob> findBobByName(final String name);

อยากรู้แต่ยังขี้เกียจทดลองอยู่
(jdk1.5 ยังใช้ feature ไม่ครบเลย)

Related link from Roti

JDBC - class.forName in Mustang

เจอใน Amit Handa's Blogs
เรื่อง JDBC Driver Loading with Mustang

ใน Mustang มีกลไกใหม่ที่ชื่อ Service Provider mechanism
ซึ่งช่วยให้ provider สามารถ describe ได้ว่าใน
jar package ของตน มีการ implement service อะไรไว้บ้าง

ซึ่งใน jdbc4.0 ก็นำกลไกนี้มาช่วยในการ solve หา Driver
จากของเดิมที่เคยเขียน

Class.forName("com.myorg.jdbc.jdbcDriverImpl");
Connection con = DriverManager.getConnection(url, user, pass);

ก็เหลือแค่
Connection con = DriverManager.getConnection(url, user, pass);

ทั้งนี้ทั้งนั้น การที่จะใช้อย่างนี้ได้
jdbc provider ต้องมีการ pack jar ในรูปของ service มาด้วย
ซึ่งผมดูวิธีการใส่ Descriptor แล้ว ก็ไม่ได้ยากอะไร
ถ้าใครไม่ได้ใส่มา เราจะมา unpack jar นั้นแล้วใส่เข้าไปเองก็ได้

Related link from Roti

Sunday, April 23, 2006

Blognone Tech Day 2006

ผ่านไปด้วยดีกับงาน Blognone Tech Day
แต่ต้องขอโทษวิทยากรคนอื่นๆ หรือ mk+lew ด้วยที่ใช้เวลาพูดนานไปหน่อย
(mk อดพูดไปเลย)
เดิมอยู่ที่บ้านก็ประมาณเวลาไว้เหมือนกัน
แต่มีข้อผิดผลาดในการประเมินเวลาเล็กน้อย (ยังเข้าข้างตัวเองอยู่ เลยใช้คำว่า เล็กน้อย) คือ
  • ตอนซ้อมจับเวลา ผมใช้วิธีพูดในใจ ไม่ได้ออกเสียง
    ถึงเวลาจริงพอออกเสียง ก็เลยช้าลง
  • ตอนช่วง demo มันควรใช้เวลาน้อยกว่านั้น
    แต่เวลาทำจริง มันตื่นเต้น มือไม้สั่น ก็เลยพิมพ์ช้าลง
    ดีนะ ที่เตรียม emacs function ไว้ช่วยจำนวนหนึ่ง
    ไม่งั้น ถึงเย็นก็ไม่เสร็จ


ส่วนประเด็นเนื้อหา ก็ได้บทเรียนที่ดี
ว่าควรจะปรับเนื้อหาอย่างไรในการ present
ตัวอย่าง present ของคุณ poonlap กับ น้องวีนนาท
เป็นตัวอย่างที่ดี ของการปรับเนื้อหาให้เหลือพอเหมาะ

ส่วนความสามารถเฉพาะตัว ต้องยกให้คุณโดม เจริญยศ
สามารถพูดเรื่องที่เราฟังไม่รู้เรื่อง ให้เราหัวเราะและสนุกได้ตลอด

ส่วนตัวอย่างที่ซับซ้อนที่สุด และดีที่สุด ต้องของ
อ. จิตร์ทัศน์ ฝักเจริญผล
เสียดายที่ยกมาพูดได้ไม่ครบ
ถ้ามีเวลาให้คิด ให้นั่งพิจารณาตาม
เราคงจะเกิดความเข้าใจใน game theory มากขึ้นกว่านี้

ZWSP ของลิ่ว ก็น่าสนใจทีเดียว
เป้าหมาย แค่ทำให้ google search คำไทยได้ นี่ก็เปลี่ยนโฉมอะไรไปได้เยอะแล้ว

ของคุณ dean4j ก็ได้ความรู้เรื่อง o-net เยอะขึ้น :)
(จริงๆแก present หัวข้อ ejb3)

Xen ของคุณ สมพล บุญจริง
ผมจิ๊ก CD ที่แกแจก กลับมาด้วย
ขอบคุณมากครับ

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

ทีมงานที่พร้อมเพรียงที่สุด
ก็ต้องทืมของคุณ ปรเมศวร์ มินศิริ
ตัวใหญ่พร้อมเพรียงกันหมดทุกคนเลย

ส่วนภาพงานที่อยากเสริมให้มีในอนาคต
(tech day มีเหมือนเดิม แต่เสริมไอ้นี่ขึ้นมา)
อาจจะเป็น workshop เล็กๆ (10-20 คน)
ที่มา meeting กันแล้วก็ show technique เล็กๆน้อย
แลกเปลี่ยนกัน เช่น ผมอาจจะ show ว่า firebug
มันช่วยอะไรผมได้

Related link from Roti