Tuesday, September 22, 2009

เมื่อวานเศร้ามาก อุตส่าห์นั่งปั่น code เพื่อเตรียม release แต่กลับพบว่า มันเปิดบน IE ไม่ได้ ช่วงหลังๆประมาทเพราะมีแต่ minor changed ทั้งนั้น เลยไม่ได้ทดสอบบน IE
แต่ไม่เป็นไร git มีเครื่องมือที่เรียกว่า 'bisect' สำหรับหาว่า commit ไหนเป็นตัวปัญหา

การใช้งานเริ่มด้วยคำสั่ง

$ git bisect start

จากนั้นก็ mark ว่า revision ที่กำลังทำงานอยู่มันไม่ดี

$ git bisect bad

บอกมันด้วยว่า revision ไหนที่มันยังดีอยู่

$ git bisect good

git ก็จะจัดการ checkout revision ที่อยู่ตรงกลางระหว่าง bad กับ good ให้
เราก็แค่บอกมันว่า revision ปัจจุบันที่ใช้งานอยู่มัน bad หรือ มัน good
กรณีของผม ผมทดสอบแล้วยัง error อยู่ก็เลยสั่ง

$ git bisect bad
Bisecting: 10 revisions left to test after this
[2c6383f3664f50b2121ba5d455d595a60c3aa85c] prototype for flex chart component.

ทำไปเรื่อยๆ จนกว่าจะจับ commit ที่มีปัญหาได้ ซึ่งมันจะฟ้องว่า

$ git bisect good
4bc966d79eb3cd7ec10672863b6c97b26f401ea7 is first bad commit
commit 4bc966d79eb3cd7ec10672863b6c97b26f401ea7
Author: pphetra
Date: Thu Aug 6 05:58:20 2009 +0000

หลังจากได้ revision ที่เป็นปัญหา ก็เป็นหน้าที่เราแล้วที่ต้องไปไล่ดู diff file ว่าอะไรที่ทำให้มันพัง

ก่อนจะออกไปก็ให้ clear สถานะ git bisect ด้วยคำสั่ง

git bisect reset


Note: กรณีที่มี Makefile ให้ run จาก command line, เราสามารถใช้คำสั่ง git bisect run ได้เลย

Related link from Roti

Monday, July 20, 2009

ทำ DSL ด้วย parser combinator

ช่วงนี้ทำระบบ billing ด้วย Grails อยู่ มันมีโจทย์ว่า user ต้องสามารถกำหนด policy การคิดเงินค่าโทรศัทพ์ได้เอง โดยรูปแบบของการคิดเงินถ้าเขียนออกมาเป็น text ก็ประมาณนี้
ถ้าเวลาที่โทรอยู่ในช่วงหนึ่งนาทีแรก ให้คิดเงินเต็มหนึ่งนาที ส่วนเวลาที่เกินให้ปัดที่หน่วยละ 6 วินาที โดยคิดหน่วยละ 10 % ของราคาต่อนาที

version แรกสุดที่ผมทำ หน้าตาออกมาประมาณนี้
[minimum: 60, nextCharge: 6, rateFunc: { x -> x * rate * 0.1}]

ไม่ต้องบอกก็รู้ตัวว่า ไม่มี user ที่ไหน config ได้แน่ มี closure หน้าตาประหลาดโผล่มาแบบนี้ (จริงๆแล้วมันคือ code ของ groovy ที่พร้อมจะ run นั่นเอง)

version ที่สอง ผมก็เลยปรับให้มันกระเดียดไปทางภาษาคนมากขึ้น หน้าตาออกมาแบบนี้
minimum 60 sec , nextcharge 6 sec : 10 %
หรือจะใช้หน่วย minute ด้วยก็ได้
minimum 1 min, nextcharge 6 sec : 10 %

เมื่อความต้องการเป็นแบบนี้ ก็ต้องหาวิธี implement, วิธีที่คุ้นเคยมากสุดก็คือใช้ Antlr เขียน Parser แต่บังเอิญเป็นคนขี้เบื่อ ก็เลยมองหาวิธีอื่นแทน ช่วงนี้ Scala กำลังมาแรง ประกอบกับเคยเห็นว่ามันทำ Parser combinator ได้ด้วย ก็เลยหวยออกที่ Scala + Parser Combinator

เริ่มแรกสุด parser ของเรา extends จาก StandardTokenParsers (มากับ Core ของ Scala อยู่แล้ว ไม่ใช่ external library)

class RateParser extends StandardTokenParsers {

}

กำหนด delimiters และ reserved word

lexical.delimiters ++= List(":", "%", ",")
lexical.reserved += ("minimum", "nextcharge", "min", "minute", "sec", "second", "m", "s")

จากนั้นก็ define grammar
ถ้าดู code จะเห็นว่าเรา define parser ย่อยๆเต็มไปหมด อันนี้แหล่ะคือความหมายของ combinator นั่นคือเราเขียน parser ใหญ่ๆ ด้วยการการเอา parser เล็กๆย่อยๆมาประกอบกันนั่นเอง
  def rule: Parser[RateStrategy] = minimum ~ nextcharge ~ percent ^^
{ case (min ~ next) ~ percent => new RateStrategy(min, next, percent)}

def minimum: Parser[Int] = "minimum" ~> unit <~ ","

def nextcharge: Parser[Int] = "nextcharge" ~> unit <~ ":"

def percent: Parser[Int] = numericLit <~ "%" ^^ (_.toInt)

def unit: Parser[Int] = minuteUnit | secondUnit

def minuteUnit: Parser[Int] = numericLit <~ ("min" | "minute" | "m") ^^ (_.toInt * 60)

def secondUnit: Parser[Int] = numericLit <~ ("sec" | "second" | "s") ^^ (_.toInt)

จะเห็นว่ามี operator หน้าตาแปลกๆ เต็มไปหมด ไม่ต้องตกใจ มาลองดูแบบง่ายสุดก่อน เริ่มที่การ parse หน่วยเวลากันก่อน
จากโจทย์ของเขา จะเห็นว่าเราจะทำการ parse พวก "1 min", "60 sec"
กรณี minute จะเห็นว่า code หน้าตาแบบนี้
  def minuteUnit: Parser[Int] = numericLit <~ ("min" | "minute" | "m") ^^ (_.toInt * 60)

def minuteUnit: Parser[Int]
ก็คือการ define method ที่ return parser ที่ return Integer (Higher order function)
numericLit <~ ("min" | "minute" | "m")
ก็คือ ระบุว่า ประโยคจะเริ่มต้นด้วย integer จากนั้นจะตามด้วย "min" หรือ "minute" หรือ "m"
เครื่องหมาย "<~" เป็น operator ที่ extend มาจาก operator "~"
operator "~" มีความหมายว่า ถ้า parse argument ทางซ้ายสำเร็จ ก็ให้ทำ ทางขวาต่อ (chain)
แต่ถ้าไม่สำเร็จ ก็ abort
ส่วน "<~" เป็นการเพิ่มความหมายว่า argument ท่ีอยู่ทางซ้ายถือเป็นตัวที่เราสนใจ ให้ ignore argument ที่อยู่ด้านขวาไปได้เลย
Note: แน่นอน เมื่อมี "<~" ก็เลยมี "~>" ด้วย
^^ (_.toInt * 60)
เราเรียก transforms operator นั่นคือ ในกรณีนี้แทนที่จะ return String ตัวเลขนาทีไป เราจะเปลี่ยนให้มันเป็น integer ก่อน

ความยุ่งยากอันถัดไปก็คือ ต้องให้มันเรียกใช้จาก Groovy ได้ (โปรเจคหลักเป็น Groovy)
โชคดีที่ Class ที่ Scala compile ออกมามันหน้าตาดีมาก ไม่มีการแปลงชื่อหรือเปลี่ยนรูปมาก
ทำให้เราสามารถเรียกใช้ได้ตรงๆ
groovy:000> f = RateStrategyParser.parse("minimum 1 min , nextcharge 6 sec : 10%")    
===> RateStrategy@34a02677
groovy:000> f
===> RateStrategy@34a02677
groovy:000> f.calc(24.00, 72)
===> 28.80

Related link from Roti

Friday, June 26, 2009

Dreyfus model

เมื่อวานได้มีโอกาสนั่งดู presentation หัวข้อ "Developing Expertise: Herding Racehorses, Racing Sheep" ของ Dave Thomas. ฟังแล้วประทับใจมากทั้งขำหัวเราะจนท้องแข็ง และปิ๊งกับเนื้อหาที่มีการใช้ metaphor เรื่องเด็กสองขวบทำให้ผม(ซึ่งมีลูกเล็กๆ 2 ขวบ) เห็นภาพชัดเจน

Theme ใน presentation ของ Dave(ที่ไม่ใช่ program dave ในหนังสือ ruby on rails ที่มีคนแปลมั่วๆไว้) กล่าวอ้างถึง Dreyfus model of skill acquisition ซึ่ง Stuart และ Hubert Dreyfus เสนอไว้เมื่อปี 1980 ว่า ในการเรียนรู้ทักษะใดๆก็ตาม มันมี 5 level ที่เราต้องผ่าน
  • Novice
  • Advance Beginner
  • Competent
  • Proficient
  • Expert
ที่น่าสนใจก็คือ Dave claim ว่าใน domain ใดๆก็ตาม พวกที่มีมากสุดก็คือ level 2 Advance Beginner, คำถามที่น่าสนใจก็คือ ทำไม? ทำไมคนส่วนใหญ่ถึงไปติดค้างอยู่ที่ระดับนั้น. บางคนก็เสนอขึ้นมาว่า เพราะเขาคิดไปเองน่ะสิว่า ระดับที่เขาอยู่นั้นเป็นระดับ 4. อันนี้ตรงกับกฎข้อที่ 1 ของ Dunning-Kruger effect ที่ว่า
Incompetent individuals tend to overestimate their own level of skill.
บางคนก็เสนอว่า ในการที่จะเลื่อนจากระดับ 2 ไประดับ 3 ได้นั้น เขาต้องการ mentor แต่จำนวนคนในระดับ 3,4,5 ไม่พอที่จะเป็น mentor ให้กับทุกคนในระดับ 2 (การเป็น mentor นั้นต้องอาศัยส่วนผสมหลายอย่างที่ลงตัว ไม่ใช่อยากจะเป็นก็เป็นได้)

Dave เขาถามผู้ฟังว่าอะไรคือความแตกต่างระหว่าง level 2 กับ level 3. ความแตกต่างที่เห็นชัดสุดก็คือ "Dependent" คนที่อยู่ระดับที่ 3 สามารถตัดสินใจได้ด้วยตัวเอง ต่างกับระดับที่ 2 ที่ต้องการให้มีคนบอกว่า ต้องทำอะไรบ้าง. สิ่งที่ตามมากับ Dependent ก็คือ "Risk". ฟังถึงตรงนี้แล้วตรงใจมาก คนส่วนใหญ่ไม่พร้อมจะเสี่ยง ทุกคนอยากอยู่ใน safety zone หรือ comfort zone

quote ที่ผมชอบสุดก็คือ ประโยคนี้
don't never ever let the expert choose your next architecture because they will choose the components that they are curious to see if it work.
ปล. 1 ในหนังสือ Pragmatic Thinking and Learning: Refactor Your Wetware มีบทที่ว่าด้วย Dreyfus Model อยู่บนหนึ่ง มีให้อ่าน free อยู่ครึ่งบทด้วย ใครสนใจไปตามอ่านได้ครับ Link (ผมอ่านแล้ว แล้วก็ลืมหมดแล้ว จนมาฟัง presentation นี้ก็เลยปิ๊งขึ้นมา)

ปล 2. ขอแสดงความเสียใจกับ Roti และ Opengis ที่ Opendream อนุญาติให้ผมเลือก components ตามใจชอบ (ตอนนี้พยายามยัด erlang ลงไปใน architecture อยู่)


Related link from Roti

Thursday, June 25, 2009

ไก่กับไข่ใน python OOP

วันนี้นั่งทำความเข้าใจกับ OOP ใน python
เนื่องจากไปเห็นว่า BaseModel ของ django มัน extend type
ก็เลยสงสัยว่าอะไรคือ object อะไรคือ type


# In Python, the __class__ attribute points to the type of an object

In [1]: object.__class__
Out[1]: <type 'type'>
# object มี type เป็น type

In [2]: type.__class__
Out[2]: <type 'type'>
# recursive structure นิ

#__bases__ attribute points to a tuple containing supertypes of an object
In [3]: object.__bases__
Out[3]: ()

In [4]: type.__bases__
Out[4]: (<type 'object'>,)
# เฮ้ยทำไม base ของ type เป็น object หล่ะ
# เจอปัญหาไก่กับไข่แล้ว

In [5]: isinstance(object, object)
Out[5]: True

In [6]: isinstance(type, object)
Out[6]: True


สรุปได้ว่า
  • <type 'object'> เป็น instance ของ <type 'type'>
  • <type 'object'> เป็น subtype ของ no object.
  • <type 'type'> เป็น instance ของตัวเอง.
  • <type 'type'> เป็น subtype ของ <type 'object'>.
<type 'type'> ก็คือ Metaclass ที่ดันเป็น subtype ของ instance ของตัวเอง

Related link from Roti

Friday, May 15, 2009

ย้าย commit ใน git

ปัญหาก็คือ branch ของผมมีหน้าตาเป็นแบบนี้

A deploy
/
D---E---F---G master

แต่ผมอยากย้าย commit G ไปอยู่ใน branch deploy
ให้มีหน้าตาแบบนี้

G--A deploy
/
D---E---F master

หลังจากนั่งทดลองอยู่นาน ก็พบว่า คำตอบนั้นง่ายนิดเดียว

git checkout master
git reset --hard HEAD^

Related link from Roti

Tuesday, April 21, 2009

pre-amp

หลวมตัวซื้อ mac มาใช้ ก็พบว่ามีหลายอย่างที่มันไม่ยอมทำให้เหมือนคนอื่น
เช่น mic input ของมันก็รับ input ที่ระดับ line-level แทนที่จะเป็น microphone-level
ซึ่งความแตกต่างของมันก็คือ ระดับของสัญญาณ
line-level มี voltage peek-to-peek ที่ระดับ millivolt
ส่วน mic-level มี voltage peek-to-peek ที่ระดับ volt

ครั้งจะไปหาซื้อ mic ของ apple มาใช้ ก็ดูเป็นการลงทุนที่ไม่คุ้มค่ายิ่งนัก
ต่อวงจรขยายเองน่าจะคุ้มกว่า
หลังจากเปิด google ไปสักพัก ก็พบวงจรนี้

เมื่อได้วงจรมา ก็ดองไว้อีกอาทิตย์กว่าๆ ก็มีอัศวินม้าขาวมาช่วยต่อวงจรให้
(อัศวินม้าขาวก็คือ "กอบ"-เพื่อนร่วมงานผม ผู้เชี่ยวชาญทั้งด้าน eclipse RCP + SWT และด้าน hardware)

ผลลัพท์ที่ได้



Related link from Roti

Monday, April 06, 2009

สรุปหนังสือจากงานหนังสือ 52

พอแก่แล้วก็เริ่มสนใจประวัติศาสตร์ ชุดนี้น่าสนใจตรงขอบเขตที่พยายามจะมองภาพรวมของภูมิภาค
  • เอเซียตะวันออกเฉียงใต้ในยุคการค้า ค.ศ. 1450-1680 เล่ม 1 ดินแดนใต้ลม (แอนโทนี รีด)
  • เอเซียตะวันออกเฉียงใต้ในยุคการค้า ค.ศ. 1450-1680 เล่ม 2 การขยายตัวและวิกฤติการณ์
เล่มนี้ของอ.เจตนา นาควัชระ  ผมสนใจหัวข้อ "สถาปัตยกรรมร่วมสมัยกับความคาดหวังของคนนอก"
  • เก่ากับใหม่ อะไรดี มนุษยศาสตร์ไทยในกระแสของความเปลี่ยนแปลง (เจตนา นาควัชระ)
สองเล่มนี้ พูดถึงประเด็นที่ไกล้เคียงกัน เล่มแรกผมสนใจการทำงานของจิตในเรื่องการคิด,  ส่วนเล่มสองเขาพูดประเด็นที่บอกว่า ระหว่าง trigger กับ action มันมี freedom อยู่, เล่มนี้ใช้แนวเขียนแบบ Story 
  • ทลายกับดักความคิด - Conceptual Blockbusting : A Guide to Better Ideas
  • พลิกคำถามเปลี่ยนชีวิต - Change Your Questions Change Your Life
เล่มนี้เป็นวรรณกรรมสำหรับเด็ก เป็นเรื่องของเด็กชาวเล (Note: ดูสิว่าจะอ่านแล้วรู้สึกทะแม่งเหมือนเรื่อง กะทิ หรือเปล่า, เรื่องกะทิกับผมมีปัญหากันตรงที่ ผมรู้สึกว่ามัน Fake) เล่มนี้กะว่าจะอ่านให้ลูกฟังก่อนนอน
  • บีตั๊ก ดาวดวงนั้นระหว่างน้ำกับฟ้า
ส่วนการ์ตูนเล่มนี้ คนเขียนเป็นคนมาเลเซีย ผมเคยเห็นลายเส้นของเขามานานแล้ว พอมีคนแปล ก็เลยตัดสินใจหยิบโดยไม่ลังเล
  • เด็กน้อยจากหมู่บ้าน The Kampung Boy ของ Lat.
ส่วนของสำนักพิมพ์มติชน คงไม่ต้องอธิบายมาก
  • เศรษฐศาสตร์แห่งชีวิต The Logic of Life
  • ประวัติศาสตร์โลกผ่านเกลือ Salt : A World History
  • ปฎิบัติการล่าไอคิว The Know-It-All
ของลูกชายได้มาสิบกว่าเล่ม เล่มที่ลูกชอบมากสุดคือเล่มนี้ เล่าตั้งแต่กำเนิดโลกยันมนุษย์ถ้ำ
  • โลกยุคก่อนประวัติศาสตร์ Prehistoric world 

Related link from Roti