Friday, October 06, 2006

ผลการวิจัยจาก google code

Rubyist มี blog ที่พูดถึง Measuring programmer happiness?
วัดโดยใช้ข้อมูลจาก google code

Related link from Roti

Thursday, October 05, 2006

Magic in Rails Routing

Jamis Buck เขาเขียนอธิบาย กลไก routing ของ Rails ว่าทำงานอย่างไร
ตอนแรกพูดถึง
Under the hood: Rails' routing DSL
ว่าด้วยการทำงานภายใน เวลา rails เริ่มอ่าน file $RAIL_ROOT/config/route.rb
จะมีการทำงานภายในอย่างไร

ส่วนตอนสองพูดถึง
Under the hood: route recognition in Rails
อธิบายว่า ถ้ามี request วิ่งเข้ามาแล้ว
กลไก routing จะ recognize url ได้อย่างไร

ส่วนที่น่าสนใจในตอนที่ 1 ก็คือ
การ dynamic generate anonymous module
แล้วค่อย include มันเข้ากับ ActionController

ส่วนตอนที่ 2 มี code ที่พิสดารมากอยู่จุดหนึ่ง ก็คือ
def recognize(path, environment={})
write_recognition
recognize path, environment
end

ความพิสดารอยู่ที่มัน recursive เรียกตัวมันเอง
แต่ก่อนที่จะเรียกตัวมันเอง มันทำการ rewrite ตัวเองด้วย method write_recognition
รูปแบบนี้เป็น lazy method แบบหนึ่ง
นั่นคือยังไม่เตรียมอะไร จนกว่าจะถูกเรียกใช้

Related link from Roti

Training Professors

BitWorking เขาลง link เรื่อง video แสดงการฝึกปลาทอง ใน youtube
แต่ที่ผมชอบไม่ใช่เรื่องนี้หรอก แต่เป็นเรื่องที่เขาเล่าให้ฟัง
She was taking a psychology class with a professor that really liked his students to take notes. He also liked to pace in front of the blackboard when he lectured. After finishing the section on Pavlov the class got together and decided to only take notes when the professor was in front of the left side of the blackboard. After a week he was only pacing there. So the next week they cut the left hand side in half and did it again. And again. They kept cutting his pacing space in half and in a month had him firmly planted on the left hand side of the blackboard.

ในอีกแง่หนึ่ง เรื่องนี้เป็นเรื่องที่เกิดตลอดเวลา ทั้งที่ตั้งใจและไม่ตั้งใจ
แต่เรา(ผู้ที่อาจโดนกระทำอยู่)จะรู้ตัวหรือเปล่า?

Related link from Roti

Wednesday, October 04, 2006

XQuery

ช่วงนี้มีโปรเจคที่ต้องยุ่งกับ XML เยอะๆอยู่ตัว
ก็เลยมองหา solution ที่มาช่วยจัดการ
หนึ่งใน solution นั้นก็คือ XQuery

query language ของ Relational Database คือ SQL
query language ของ XML ก็คือ XQuery

ตัว syntax ของ XQuery มีบางคนเรียกย่อๆว่า FLWOR
ซื่อย่อมาจาก causes หลักๆที่ XQuery support นั่นคือ
  • F -> For
  • L -> Let
  • W -> Where
  • O -> Order by
  • R -> Return

มาตรฐานของ XQuery จะ depend อยู่บน มาตรฐานของ XPath 2.0
นั่นคือการอ้างถึง element ต่างๆ จะทำผ่าน XPath expression
ใครอยากเห็นว่าหน้าตา syntax เป็นอย่างไร ให้ดูที่ link นี้
Blooming FLWOR - An Introduction to the XQuery FLWOR Expression

ตัว language เห็นบางคนก็บอกว่า มีแนวทางไปในทางเดียวกับ Functional Language
อ่านดูได้ใน XQuery: a typed functional language for querying XML
ส่วนบางคนก็บอกว่า XQuery is imperative
ถ้ามีสองความคิดเห็นอย่างนี้ แสดงว่า xquery มันน่าอยู่กลางๆ spectrum ที่ฝั่งซ้ายเป็น declarative
ส่วน ฝั่งขวาเป็น imperative
(ไม่ว่าจะเป็นอะไร ก็ช่างหัวมันเถิด ใช้งานได้ดีก็พอแล้ว)

ผมชอบความ powerful ของมัน ลองดูตัวอย่างนี้
สมมติเรามี xml ที่ present Part ในลักษณะ Flat อยู่
<?xml version="1.0" encoding="ISO-8859-1"?>
<partlist>
<part partid="0" name="car"/>
<part partid="1" partof="0" name="engine"/>
<part partid="2" partof="0" name="door"/>
<part partid="3" partof="1" name="piston"/>
<part partid="4" partof="2" name="window"/>
<part partid="5" partof="2" name="lock"/>
<part partid="10" name="skateboard"/>
<part partid="11" partof="10" name="board"/>
<part partid="12" partof="10" name="wheel"/>
<part partid="20" name="canoe"/>
</partlist>

ถ้าเราต้องการ convert ให้เป็นแบบนี้
<parttree>
<part partid="0" name="car">
<part partid="1" name="engine">
<part partid="3" name="piston"/>
</part>
<part partid="2" name="door">
<part partid="4" name="window"/>
<part partid="5" name="lock"/>
</part>
</part>
<part partid="10" name="skateboard">
<part partid="11" name="board"/>
<part partid="12" name="wheel"/>
</part>
<part partid="20" name="canoe"/>
</parttree>

เราสามารถทำได้ โดยเขียน XQuery ในแบบนี้
declare function local:one_level($p as element()) as element()
{
<part partid="{ $p/@partid }"
name="{ $p/@name }" >
{
for $s in doc("partlist.xml")//part
where $s/@partof = $p/@partid
return local:one_level($s)
}
</part>
};

<parttree>
{
for $p in doc("partlist.xml")//part[empty(@partof)]
return local:one_level($p)
}
</parttree>

ช่วงนี้เพื่อทดสอบความเป็นไปได้ต่างๆ ผมก็เลยลองหา Opensource มาเล่นก่อน
ตัวที่น่าสนใจก็คือ eXist
ซึ่งเจ้านี้ claim ว่า XQuery ของเขา test ตามมาตรฐานของ w3c ผ่านกว่า 80% แล้ว

Architecture ของ eXist (ในแง่ implement) ก็น่าสนใจ ตรงที่ Framework ที่เขาใช้เขียน server
base อยู่บน Cocoon ซึ่งเป็น Development Framework ที่อิงกับ XML อย่างแนบแน่น

Related link from Roti

Tuesday, October 03, 2006

IEs4Linux



ช่วงหลังๆนี่ ละเลย IE มาตลอด (2 ปีแล้ว)
อย่างบางโปรเจคที่บังคับให้ใช้ firefox ได้ ผมก็จะ implement โดยไม่สนใจ IE เลย
(แต่จะมีน้องๆที่เสียดาย IE มาคอย port ให้ IE ใช้ได้)

มีโปรเจคใหม่อยู่ตัว ที่ต้อง support IE แน่ๆ
แต่เนื่องจากเครื่องที่ใช้เป็น Linux กับ Mac
ก็เลยต้องขวนขวายมากกว่าปกติ

เดิมมองไว้ที่ vmware
แต่ลองแล้ว มันหนักไปหน่อย
สุดท้ายก็ไปลงตัวที่ IEs4Linux
ซึ่ง run โดยใช้ Wine
การติดตั้งก็ง่ายมาก (ผมใช้ fedora)
ลงทีเดียวได้ครบตั้งแต่ version 5, 5.5, 6
ใครสนใจก็ลองดูได้

Related link from Roti

Monday, October 02, 2006

Prevayler

มองหา Persistent Storage ที่เหมาะๆมานานแล้ว
วันนี้ได้ฤกษ์ลองเล่น ​Prevayler ดู
(จริงๆ แล้ว prevayler มีมานานมากแล้ว
แต่ด้วย nature ของผมที่เมื่อก่อนเป็นพวก emotionally attached to database
พอเห็นคำเปรยที่ว่า Memory Only ก็เดินหนีแล้ว
)

ลองดู Architecture ก่อน
  • Prevayler maintain ข้อมูลใน Memory เท่านั้น
  • ข้อมูลที่ maintain อยู่ในรูป Plain Old Java Object
  • เนื่องจากข้อมูลเก็บอยู่บน Memory เป็นหลัก
    เพื่อให้ persistent สามารถ keep state ได้
    prevayler ใช้วิธีทำ snapshot ลงบน Disk
  • การแก้ไขข้อมูลจะต้องทำผ่าน Transaction
    โดยใช้ pattern ที่เรียกว่า Command pattern
  • เมื่อเราสั่ง execute Command Object(Transaction)
    Prevayler จะทำการ serialize Command Object ของเราลง Journal file ก่อนที่ update ข้อมูลใน memory
    เพื่อทีในกรณีที่ system fail ก่อนที่จะทำ snapshot
    จะได้สามารถทำ recover persistent state กลับมาได้

ฟังดูแล้ว ก็น่าสนใจดี

ลองดูภาพการใช้งานจริง
สมมติ application ตัวอย่างเป็น Bank application
ที่ต้อง maintain account ของ customer

ใน prevayler ไม่มี concept เรื่อง table แบบ Relational DB
ข้อมูลที่จะเก็บลง Prevayler ต้องอยู่ในรูป Object
ดังนั้นเราจึง define Bank Class ขึ้นมา เพื่อใช้ maintain account object ของเรา
public class Bank implements Serializable {

private static final long serialVersionUID = -3472784405094724103L;

public List<Account> accounts = new ArrayList<Account>();

public List<Account> getAccounts() {
return accounts;
}

public void addAccount(Account acct) {
accounts.add(acct);
}

}

ตัว Account Class ก็เขียนง่ายๆดังนี้
public class Account implements Serializable {

private static final long serialVersionUID = 5447177127896043827L;

private String code;
private BigDecimal amount;

public Account(String code, BigDecimal amount) {
this.code = code;
this.amount = amount;
}

... getter/setter here.

}


เนื่องจากกลไกที่ prevayler ใช้ในการทำ snapshot
ก็คือ java serialize ธรรมดา (ตรงนี้สามารถเปลี่ยนวิธีได้ เช่นไปใช้ xml serialize)
ดังนั้น class Bank กับ Account ของเรา ก็เลยต้อง implement Serializable

การเริ่่มต้นใช้งาน prevayler จะเริ่มต้นดังนี้
Prevayler prevayler = PrevaylerFactory.createPrevayler(new Bank(), "bank");     
Bank bank = (Bank) prevayler.prevalentSystem();


ในการที่จะสร้าง Account ขึ้นมา, เราจะไม่ใช้วิธี access Bank Object ตรงๆ
แต่จะทำผ่าน Command Object
ลองดูตัวอย่าง Command Object ที่ใช้ create Account
public class CreateAccount implements Transaction {

private static final long serialVersionUID = 8524963860312931007L;

private Account account;

public CreateAccount(Account account) {
this.account = account;
}

public void executeOn(Object prevalentSystem, Date executionTime) {
Bank bank = (Bank) prevalentSystem;
bank.addAccount(account);
}

}

เมื่อจะใช้งาน ก็สั่งผ่าน prevayler object
prevayler.execute(new CreateAccount(new Account("11", new BigDecimal("200.00"))));


ที่นี้ก็มาถึงคำถามถึงจุดนี้ถ้าเราปิดโปรแกรมเราลงไป แล้วเปิดขึ้นมาใหม่
Bank Object เราจะยังมี Account Object ที่พึ่งสร้างอยู่หรือไม่
คำตอบก็คือ "มี"
เพราะเมื่อเราสั่ง execute Command Object เมื่อไร
prevayler จะทำการสร้าง journal file ขึ้นมา
(1 command ต่อ 1 journal file)
กลไกการเขียน journal ก็ใช้ java serialize ธรรมดา

ที่นี้การเก็บข้อมูลในรูป journal อย่างเดียวคงไม่เหมาะแน่
เพราะมันจะเยอะแยะไปหมด และน่าจะกินเวลา startup time
(prevayler cliam ว่าสามารถ execute journal ใน rate 6000 journal/sec.)
prevayler ก็เลยมีความสามารถในการทำ snapshot ด้วย
โดยการสั่ง
prevayler.takeSnapshot();


หลังจากทดลองเล่น + อ่าน Architecture แล้ว
ก็จัดการ add เข้า Collection Tools ของตัวเอง
โดย usecase ที่จะนำไปใช้ ก็คือ
  • พวก Desktop Application ตัวเล็กๆ
  • กลไก Data บางอย่างที่ขี้เกียจทำ ORM (เริ่มเบื่อแล้ว)
    เช่น User preference ใน Web application
  • เอาไว้เก็บพวก workflow instance ก็ไม่เลว
  • เก็บ Fact ของพวก rule base ก็น่าจะได้


ข้อเตือนใจ
  • Prevayler maintain ทุกอย่างใน memory
    snapshot เป็นแค่ backup
    ดังนั้นต้องแน่ใจว่ามี Ram พอ, กับข้อมูลไม่เยอะจนเกินไป
  • อย่าไปนึกว่าจะมี กลไก Index แบบ Relational database
    การ access object เป็นไปตาม java object ธรรมดา
    ดังนั้นอะไรที่อยากให้ access เร็ว ก็ต้องใช้พวก Map
  • ถ้า Domain เราซับซ้อน
    command object ก็จะมีปริมาณสูง ทำให้ maintain ลำบากขึ้น (อะไร,อยู่ที่ไหน)

Related link from Roti

Friday, September 29, 2006

Agile

บทบ่นล่าสุดของ Steve Yegge ,Good-Agile-Bad-Agile
พูดถึง Agile software developement
(คนอะไร เขียน blog โคตรยาวเลย, ผมขี้เกียจอ่านทั้งหมด ก็เลยเลือก scan อ่าน)
ในประเด็นว่า อะไรที่ชอบ อะไรที่ไม่ชอบ
แล้่วก็ยกตัวอย่าง บรรยากาศที่ทำงานของ Google ว่ามันเจ๋งอย่างไร

- there are managers, sort of, but most of them code at least half-time, making them more like tech leads.
(บริษัทฯเราก็เข้าข่ายนี้เหมือนกัน)

- developers can switch teams and/or projects any time they want, no questions asked; just say the word and the movers will show up the next day to put you in your new office with your new team.

- Google has a philosophy of not ever telling developers what to work on, and they take it pretty seriously.

- developers are strongly encouraged to spend 20% of their time (and I mean their M-F, 8-5 time, not weekends or personal time) working on whatever they want, as long as it's not their main project.
(อ้า ข้อนี้ก็ตรงกัน แต่ของเราเผลอๆ สัดส่วนอาจมากกว่า 20 %)

- there aren't very many meetings. I'd say an average developer attends perhaps 3 meetings a week, including their 1:1 with their lead.
(อันนี้ บริษัทฯ ผมน้อยกว่ามาก, บางอาทิตย์ก็ไม่มี meeting)

- it's quiet. Engineers are quietly focused on their work, as individuals or sometimes in little groups or 2 to 5.
(ไม่เหมือนกัน ที่บริษัทฯของผมเสียงดังมาก
บางวันก็มีเสียงร้องให้ของลูกชายผมด้วย)

- there aren't Gantt charts or date-task-owner spreadsheets or any other visible project-management artifacts in evidence, not that I've ever seen.
(ของผมนานๆจะมีที โดยมากมักจะมีในช่วงเริ่มต้นโครงการ)

ส่วนที่ชอบก็คงในส่วน comment ที่มีคนตอบกลับ
(ยาวกว่าบทบ่นอีก)
มีที่ตรงใจอยู่อันหนึ่ง Link
ก็คือ Agile มันเป็นเรื่องของ culture
เพราะเมื่อต้นอาทิตย์ก็ได้เข้าไปที่ ตลาดหลักทรัพย์ฯ
โดยเข้าไปอธิบายเรื่อง methodology ที่บริษัทฯใช้อยู่
(เนื่องจากจะมีโปรเจคที่ต้องทำร่วมกัน ก็เลยต้องแลกเปลี่ยนกันก่อน)
ก็สัมผัสได้ถึง mismatch ของวัฒนธรรมองค์กรอยู่เหมือนกัน

Related link from Roti

Thursday, September 28, 2006

Nuxeo & OSGi

Nuxeo ก็เป็นอีกรายที่เปลี่ยน Architecture มาใช้ OSGi
ลองอ่านเหตุผลในการ switch ของเขาดู Link

ตัวอย่าง use case ในการใช้ extension-point ของ Nuxeo ก็เช่น
  • define actions and menus
  • define content schemas
  • define views
  • define content objects
  • define permissions
  • define PageFlows
  • define Business Process
  • define content trnsformations
  • define rule for rule engine
  • define script extension (JRuby, Jython,...)
  • define JMS Event queue
  • define event type
  • define security policies
  • define Access Control Policies
  • define Storage Backend
  • define query engine
  • define indexing engine


ใครที่ยังไม่เคยเห็น Architecture ของ OSGi ขอแนะนำให้ทดลองเล่นหรืออ่านดูครับ
โดยเฉพาะ model ในส่วน Extension Point หรือ Plugin
ออกแบบได้งามมากๆ

Related link from Roti

Wednesday, September 27, 2006

My Neighbor Totoro



หนังเรื่อง My Neighbor Totoro กลายเป็นหนังเรื่องโปรดของครอบครัวผมไปแล้ว
ไม่ว่าจะเป็น พ่อ แม่ ปู่ ย่า หรือ เจ้าลูกชาย

หนังเรื่องนี้เป็นหนังที่ดูซ้ำได้โดยไม่เบื่อ
ผมดูกับลูกชายไปสามรอบแล้ว ก็ยังสนุกอยู่
(เมื่อกี๊แฟนเดินมาแซวว่า ของฉันดูไปห้ารอบแล้ว)

Related link from Roti

Friday, September 22, 2006

Java กับ Tail-Recursive

คุณสมบัติอย่างหนึ่ง ของภาษาคอมพิวเตอร์ในตระกูล Functional language (lisp, haskell, erlang)
ก็คือ ต้องสามารถ optimize tail-recursive ได้
โดยการ call แบบนี้ จะไม่มีการใช้ stack
เพื่อป้องกันการเกิดปัญหา stack overflow
(เนื่องจาก nature ของ Functional Language
มันส่งเสริมให้ใช้ recursive)

พึ่งรู้ว่า IBM JRE สามารถทำ optimize tail-recursive ได้เหมือนกัน
โดยทำ ณ ขณะ runtime (ไม่ได้ทำตอน compile)
ทดลองเขียนโปรแกรมทดสอบง่ายๆดู
public class TestRecursive {

public int run(int i) {
return run(i);
}

public static void main(String[] args) {
new TestRecursive().run(10);
}

}

ทดลอง run ใน jre ของ IBM มันจะ run ไปเรื่อยๆไม่รู้จบ
แต่ถ้าเป็นเจ้าอื่น จะเกิด Stack overflow ในพริบตา

เท่าที่ทดลองดู ยังเห็นแค่มี jre (1.4) ของ IBM เท่านั้นที่ทำได้
ของ Sun (1.5), BEA (1.4), Mac (1.5) ทำแบบนี้ไม่ได้

Related link from Roti

ผลกระทบเล็กๆของการปลด คตง.

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

Related link from Roti

Rails in Academia

ลองอ่าน comment ดูว่ามึใครเข้าใช้ทำอะไรบ้าง
Link

Related link from Roti

Codefest #2

กลับมาอีกรอบแล้ว สำหรับกิจกรรมเขียนโปรแกรม CodeFest
หลายคนมักจะเข้าใจผิดนะว่า CodeFest เป็นการแข่งขัน
จริงๆแล้วมันเป็นกิจกรรมแลกเปลี่ยนประสบการณ์
(อันนี้ไม่ตรงนิยามแบบที่ฝรั่งเขาทำเท่าไร แต่จะเป็นไรไปหล่ะ
ในเมื่อบริบทเมืองไทย มันคนละอย่างกับเขา)

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

ที่อยากคุยก็คือ อยากให้น้องๆที่เข้าร่วม
เห็นภาพที่ไกลกว่าที่เขาเคยเห็น
(เช่นครั้งที่แล้วในกลุ่มผมคนที่เคยเขียนแต่ C, php ก็ได้เห็น erlang, python, dojo)
โดยมีโจทย์ที่น่าสนใจก็คือ
ทำอย่างไร จะเปลี่ยนจากคนที่ นัยตาขุ่นทึบ เป็นนัยตาวิบวับ ได้
(อันนี้ขออธิบายหน่อย
ไม่รู้ว่าเคยสังเกตกันหรือเปล่าว่า
เวลาเราอธิบายเรื่องที่เราคิดว่ามันน่าสนใจให้กับคนที่ไม่เคยรับรู้เรื่องนั้นมาก่อน
ถ้าเราสังเกตดูที่ดวงตาของเขา เราจะเห็นว่ามันลอยๆ ขุ่นๆ ไม่มีประกาย
แต่ถ้าเมื่อไรก็ตามที่เขา get และสนุก กับเรื่องนั้น
ดวงตาก็จะเปลี่ยนเป็นมีประกายวิบวับขึ้นมาทันที)
(พฤติกรรมนี้ เข้าข่ายศัพท์ที่ mk เรียกว่า เผยแพร่ลัทธิ)

อ้ออีกข้อหนึ่งที่อยากคุยก็คือ
อยากให้ตัวเองเห็นภาพไกลกว่าที่ตัวเองคิดเช่นเดียวกัน

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

ปล.2 codefest ของเราใช้ชื่อว่า การเขียนโปรแกรมมาราธอน
ในวงการอื่นๆก็มีกิจกรรมมาราธอนแบบนี้เหมือนกัน
ลองดู SketchCrawl ซึ่งเป็นกิจกรรม drawing มาราธอน

Related link from Roti

Thursday, September 21, 2006

Breath Holding Spell

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

อยู่โรงพยาบาล ก็ไม่มีอะไรมาก นอนรับน้ำเกลือเป็นหลัก
แต่ที่ติดใจก็คือ อาการแข็งเกร็ง หยุดหายใจ นั้นเกิดจากอะไร, เรียกว่าอะไร
ผลการตรวจเลือก ค่าที่ตกนอก range ก็คือ potassium ซึ่งมีสูงกว่าปกติ
แล้วก็ co2 ซึ่งมีน้อยกว่าปกติ
สงสัยในเรื่อง co2 ก็เลยเปิดหนังสือค้นหา ก็มีอาการชักอันหนึ่งที่เรียกว่า
Hyperventilation
ที่มีอาการใจผิดรูปแบบ จน co2 ในร่างกายอยู่ในระดับต่ำ
ส่งผลให้ปริมาณ calcium ในร่างกายน้อยลง ทำให้เกิดอาการมือจีบเกร็ง

อีก 2 วันต่อมาได้คุยกับหมอว่า มีอาการแบบนี้นะ จะใช่ Hyperventilation หรือเปล่า
หมอก็บอกว่า ไม่น่าจะใช่ น่าจะเป็น Breath Holding Spell เสียมากกว่า
อ่านดูแล้ว ก็อาการตรงกับที่ลูกเราเป็น
ยกเว้นว่า ช่วงเวลาที่เขาพูดถึง เขาบอกว่าส่วนใหญ่จะเป็นประมาณ 30 วินาที
และนานสุดก็มักจะไม่เกิน 1 นาที
ส่วนลูกผมดูแล้ว น่าจะเกิด 1 นาทีนะ
แต่ไม่รู้ว่าเท่าไรแน่ เพราะเวลาที่ตกใจ เวลาในความรู้สึกเรามักจะกินเวลานานเกิดกว่าเวลาจริงเสมอ

ส่วนวิธีแก้ไข คุณหมอบอกวิธีว่า
ถ้าเกิด Breath Holding Spell แล้ว ก็ให้เราบีบที่เอ็นร้อยหวายของลูกแรงๆ
ถ้ายังไม่หายอีก ก็ให้เป่าปาก เพื่อช่วยเอาออกซิเจน เข้าไปเลี้ยงสมอง

Related link from Roti

Thursday, September 14, 2006

CAB vs. RCP

CAB (Composite UI Application Block) จากค่าย Microsoft
กับ RCP (Rich Client Platform) จากค่าย Eclipse, IBM
มีอะไรที่เหมือนกัน?

ลองอ่าน Eclipse and Microsoft: parallel universes

Related link from Roti

Tuesday, September 12, 2006

amb

amb หรือ Angelic Operator เป็น operator ที่มีเฉพาะใน
language ที่ support continuations เท่านั้น
(scheme, ruby, ...)
Angelic Operator มีชื่อเรียกอีกชื่อคือ "McCarthy's Ambiguous Operator
(John McCarthy คือคนที่สร้าง Lisp ขึ้นมา)

ลองดูความพิสดารของมันกัน
(โจทย์จาก ruby quiz #70)
begin
a = amb 0,1,2,3,4
b = amb 0,1,2,3,4
c = amb 0,1,2,3,4

amb unless a < b
amb unless a + b == c
puts "a = #{a}, b = #{b}, c = #{c}"
amb
rescue
puts "no more solution."
end

ผลลัพท์ที่ได้ จะมีหน้าตาแบบนี้
irb(main):063:0> 
a = 0, b = 1, c = 1
a = 0, b = 2, c = 2
a = 0, b = 3, c = 3
a = 0, b = 4, c = 4
a = 1, b = 2, c = 3
a = 1, b = 3, c = 4
no more solution.
nil

โดยในตอนแรกที่เราสั่ง
a = amb 0,1,2,3,4

a จะมีค่าเป็น 0
ส่วน b และ c ก็จะเริ่มต้นที่ 0 เช่นเดียวกัน
จากนั้นเมื่อถึงบรรทัดที่
amb unless a < b

ณ จุดที่ evaluate นี้ a กับ b มีค่า เท่ากับ 0
ดังนั้นมันจะเกิดการเรียกใช้ amb แบบไม่มี parameter
ซึ่งจะทำให้เกิดการ backtrack ย้อนกลับไปให้เลือกค่า a, b ใหม่
จนได้ค่า a = 0, b = 1 มา จึงจะผ่านบรรทัดนี้ไปได้

key สำคัญก็คือการ backtrack ซึ่งเขา implement โดยใช้ contiunation
ตัวอย่างการ implement amb โดย Jim Weirich
มีหน้าตาแบบนี้
class Amb

class ExhaustedError < RuntimeError; end

def initialize
@fail = proc { fail ExhaustedError, "amb tree exhausted" }
end

def choose(*choices)
prev_fail = @fail
callcc { |sk|
choices.each { |choice|
callcc { |fk|
@fail = proc {
@fail = prev_fail
fk.call(:fail)
}
if choice.respond_to? :call
sk.call(choice.call)
else
sk.call(choice)
end
}
}
@fail.call
}
end

def failure
choose
end

def assert(cond)
failure unless cond
end
end

เห็นแล้วตาลาย เพราะเขา port มาจากตัวอย่างใน Teach Yourself Scheme in Fixnum Days โดยตรง
มันมีกลิ่นของ funtional language เยอะไปหน่อย

แต่ลองดูตัวอย่างที่ Eric Kidd implement ไว้อีกแบบ
อันนี้มีกลิ่น imperative language เยอะหน่อย ทำให้ดูเข้าใจง่ายขึ้น

# A list of places we can "rewind" to
# if we encounter amb with no
# arguments.
$backtrack_points = []

# Rewind to our most recent backtrack
# point.
def backtrack
if $backtrack_points.empty?
raise "Can't backtrack"
else
$backtrack_points.pop.call
end
end

# Recursive implementation of the
# amb operator.
def amb *choices
# Fail if we have no arguments.
backtrack if choices.empty?
callcc {|cc|
# cc contains the "current
# continuation". When called,
# it will make the program
# rewind to the end of this block.
$backtrack_points.push cc

# Return our first argument.
return choices[0]
}

# We only get here if we backtrack
# using the stored value of cc,
# above. We call amb recursively
# with the arguments we didn't use.
amb *choices[1...choices.length]
end

# Backtracking beyond a call to cut
# is strictly forbidden.
def cut
$backtrack_points = []
end

ดูง่ายกว่ากันเยอะเลย

ลอง implement โจทย์เดียวกันนี้ใน scheme บ้าง
(สบายหน่อย ตรง scheme มี library amb มาให้อยู่แล้ว)
หน้าตาโปรแกรมออกมาแบบนี้
(require (lib "extra.ss" "swindle"))

(define assert
(lambda (pred)
(if (not pred) (amb))))

(define solve
(lambda ()
(let ((a (amb 0 1 2 3 4))
(b (amb 0 1 2 3 4))
(c (amb 0 1 2 3 4)))
(assert (< a b))
(assert (equal? (+ a b) c))

(printf "a=~a, b=~a, c=~a\n" a b c)
(amb))))

Related link from Roti

Saturday, September 09, 2006

กลุ่มคนที่สนใจ Erlang

ปกติในแวดวงของ erlang จะเงียบๆ ใครใช้ก็ใช้ไป
แต่หลังจากที่ Yariv Sadan เริ่มเขียน blog เกี่ยวกับ erlang
ก็ปรากฎว่ามีคนให้ความสนใจมากขึ้น

Yariv เขาเล่าว่า ก่อนเขียนเรื่อง erlang,
web เขามีคนมาเยี่ยมดูหลัก 10 คนต่อวัน
แต่พอหลังจากเขียนเรื่องนี้ จำนวนคนที่เข้ามาดูเพิ่มขึ้นเป็นหลักพัน

อันนี้้เป็นแผนที่ที่ได้จาก google analytic
แสดงว่า visitor มาจากที่ไหนบ้าง



ปล. ผมมั่นใจมากว่าจุดบน bangkok นี่ ของผมแน่นอน

Related link from Roti

Friday, September 08, 2006

Law of Demeter

ช่วงนี้หากินกับน้องๆในบริษัทดีกว่า
ลองดู statement ที่น้องใหม่เขียน
line = repOut.getPages().get(pageIndex-1).getLines().get(lineIndex-1);

วัตถุประสงค์ของบรรทัดข้างบน
ก็คือต้องการดึง current Line ขึ้นมา

ประเด็นก็คือ มัน(class ที่ implement method นี้)ล้วงลูกไปไกลเหลือเกิน
แถมยังรู้มากด้วย โดย method นี้รู้หมดว่า page เก็บอยู่ใน List Structure
ส่วน line ก็เก็บใน List เช่นเดียวกัน

ปัญหาของการล้วงลูก หรือรู้มาก ก็คือ
ในอนาคต ถ้ามีการปรับเปลี่ยน structure ของ page หรือ line เมื่อไร
จำนวน code ที่จะโดน effect ก็จะเยอะตามไปด้วย

ใน OO มันมีกฎอยู่ข้อหนึ่ง ก็คือ "Law of Demeter"
อธิบายสั้นๆว่า "Only talk to your friends"
ดังนั้นถ้าเขียนให้ถูกตามกฎของ Law of Demeter เราควรจะเขียนแค่นี้พอ
line = repOut.getCurrentLine()


Good fences make good neighbors.
Robert Frost, "Mending Wall"

** ประโยคเด็ดข้างบน ลอกจาก "The Pragmatic Programmer, from journeyman to master"
บทที่ว่าด้วยเรื่อง "Decoupling and the Law of Demeter"

Related link from Roti

Sun & JRuby

น่าสนใจมาก
Sun จ้างคนเขียน JRuby 2 คน เข้าทำงาน full time แล้ว
หน้าที่คือพัฒนา JRuby ให้แตะ 1.0 ให้ได้
และยังต้องคิดถึง developer tool ว่าควรจะเป็นอย่างไรด้วย

ส่วน licenses ของ JRuby ยังเป็น open source เหมือนเดิม

JRuby Steps Into the Sun
JRuby Shines in Sun
JRuby Guys

Related link from Roti

Thursday, September 07, 2006

ประตูสามบาน

เมื่อวันก่อนตอนประชุมกัน มีการหยิบยกโจทย์ประตูสามบานขึ้นมาคุยกัน
จำได้ว่าเคยอ่านเจอใน blog ของ ฮุ้ย ก็เลยไปค้นเจอหัวข้อ ปริศนาเกมส์โชว์
ในนั้นมีการอ้างถึงหนังสือ "Information Theory, Inference and Learning Algorithms"
ก็เลย download มาดูเฉลย

[กรุณาอ่านโจทย์ใน link ก่อน แล้วค่อยอ่านข้างล่างนี้]
ใน commonsense ของเรา เราก็ต้องบอกว่า chance ของการได้ทอง
มันเหลือ 50-50 แล้ว การเปลี่ยนหรือการไม่เปลี่ยน ควรจะมีความน่าจะเป็นเท่าๆกัน
แต่หลังจากอ่านเฉลย ทำให้เรารู้ว่ามันมี event หนึ่งที่เราลืมคิดไป
นั่นก็คือ event ของ พิธีกรเกมส์โชว์ ที่เลือกเปิดประตูเบอร์ 3
event นั้นมีการกระจายตัวที่ไม่เท่ากัน เช่น

สมมติว่าถ้าทองอยู่ที่ประตู 1, พิธีกร จะเลือกเปิดประตู 2 หรือ 3 ก็ได้
ดังนั้นโอกาสที่จะเปิดประตู 3 มีค่าเท่ากับ 50%
แต่ถ้าทองอยู่ที่ประตู 2 , พิธีกร มีทางเลือกแค่ทางเดียวในการเปิดประตู
ดังนั้นโอกาสที่จะเปิดประตู 3 มีค่าเป็น 100%

ในเฉลย เขาเอา Bayes' theorem เข้ามาคำนวณ
ซึ่งสำหรับคนที่ไม่คุ้นกับ language ทางคณิตศาสตร์ (เช่นผม)
ก็ต้องใช้เวลา absorb นานหน่อย

แต่สำหรับคนที่ขี้เกียจอ่าน math language
ก็มีเฉลยอีกแบบ ที่เขาเรียกว่า "more intuitive"
ก็คือให้ลองคิดโจทย์นี้ใหม่ โดยจับโจทย์มาขยาย scale
เปลี่ยนเป็นว่า มีประตูอยู่ 1,000,000 ประตู
เราเลือกประตูเบอร์ 1, พิธีกรเปิดประตู 999,998 ประตูที่เหลือ
เพื่อโชว์ว่าไม่มีทองในประตูเหล่านี้
ถามว่าเราจะยังเลือกประตูเบอร์ 1 อยู่หรือไม่ หรือจะเปลี่ยนไปเลือกอีกประตูหนึ่งดี

พอเปลี่ยน scale โจทย์มาแบบนี้ ก็เลย Bingo เลย
ถ้าเปลี่ยนประตู โอกาสชนะนี้เกือบ 100% เลย
เพราะในการเลือกครั้งแรก เรามี chance อยู่แค่ 1 ใน 1,000,000 เท่านั้นเอง

ps. ใน link ของฮุ้ยมีโปรแกรม simulation ที่ otto เขียนไว้
แต่เนื่องจากทืม mm.co.th กลับจากญี่ปุ่นกันหมดแล้ว
link ก็เลยหายไปด้วย
ผมเลยเขียนโปรแกรม simulate ใหม่ขึ้นมา
def rand_door
rand(3) + 1
end

def open_second_door(gold_door, first_guess)
doors = [1,2,3]
doors.delete(gold_door)
doors.delete(first_guess)
doors[rand(doors.size)]
end

def choose_left_door(first_guess, opened_door)
(1..3).each {|door|
return door if (door != first_guess && door != opened_door)
}
end

def play
gold_door = rand_door
first_guess = rand_door
opened_door = open_second_door(gold_door, first_guess)
left_door = choose_left_door(first_guess, opened_door)
result = gold_door == left_door ? "win" : "loss"
puts <<-EOS
Game begin.
You don't see this. -> (Gold is at
#{gold_door})
First. you choose door number
#{first_guess}.
I open door number
#{opened_door}.
So. You chnage your mind to door number
#{left_door}.

== You
#{result}. ==

EOS
gold_door == left_door ? 1 : 0
end

win = 0
loops = 30
loops.times do
win += play
end
puts "------------------"
puts "Play
#{loops}, win #{win}"

Related link from Roti