Thursday, June 15, 2006

Dabbawallahs สุดยอด logistic

วันนี้นั่งดูรายการ Discovery channel เจอสารคดี
เกีี่ยวกับ "dabbawallahs"

"dabbawallash" เป็นชื่อของระบบการขนส่ง
ที่ใช้ขนส่งอาหารกลางวัน
โดยเรื่องของเรื่องก็คือ มีคน india ใน Mumbai จำนวนหนึ่ง
ที่ต้องกินข้าวกลางวันที่ทำจากบ้านตัวเองเท่านั้น
(อาจจะเป็นเหตุผลทางศาสนา หรือความเชื่อ)
ก็เลยเกิดเครือข่ายในการขนส่งขึ้น

ด้วยการไปรับปิ่นโตตามบ้านที่เหล่าภรรยาเตรียมไว้
จากนั้นก็รวบรวมแล้วนำส่งไปยังที่ทำงานของเหล่าบรรดาสามี
โดยใช้ทั้งการเดิน, ขี่จักรยาน, รถไฟ, รถเข็น
ระยะทางที่ขนส่ง ไม่มากเลย
a typical customer commutes about 100 kms a day between his home and work place.

(อย่าลืมหาร 2 หล่ะ)
น้ำหนักของการแบกเดิน ก็ไม่มาก
carrying a load of 100 kgs. mannually on their head and walk 2.5 kms.


น่าทึ่ง ที่ระบบนี้มีมา 120 ปีแล้ว
ในปี 2005 มีปริมาณอาหารที่ต้องส่ง 150,000 box, 300,000 transaction ต่อวัน
(บริการเก็บกลับบ้านให้ด้วย)
ใช้พนักงาน 5000 คน
ความผิดผลาดน้อยมาก
reported less than six errors in 13 million transaction


การจัดทืม จะแบ่งให้แต่ละคนรับผิดชอบอาหาร 30 ชุด
ทืมหนึ่งมี 8 คน
8 ทืมรวมเป็น 1 group
มี group ทั้งหมด 120 group

เริ่ม process ด้วยการไปรับอาหารจากบ้านต่างๆ ประมาณ 8.30-9.00
จากนั้นก็จะขนอาหารมารวมกันที่สถานีรถไฟ
ถึงตอนนี้ ก็เป็นเวลา Sorting แล้ว
ตรงนี้ต้องใช้ระบบรหัสมาช่วย
code ของแต่ละปิ่นโต จะประกอบด้วย
  • origin of the lunch box
  • assocated collection team member
  • destination
  • corresponding delivery team member
  • location building identification and floor number

อาหารไปถึงลูกค้าไม่เกินบ่ายโมง
จากนั้น 3.30pm ก็ได้เวลาขนปิ่นโตกลับบ้าน

paper อ่านได้ที่นี่
World class logistics operations: The case of Bombay Dabbawallash
รูป ดูได้ที่นี่
http://perso.orange.fr/laurentallard/Les_Enfants_de_Gandhi/dabbawallahs.html

Related link from Roti

เปรียบเทียบ Dojo กับ Prototype

เดิมที่ผมใช้ ruby on rails อยู่นั้น
Prototype ถือเป็นพระเอกในฝั่ง javascript
ช่วงนี้หันมาทำงานด้วย Tapestry4
Tacos ซึ่งเป็น Ajax component ของ Tapestry
ดันใช้ Dojo เป็นหลัก
ก็เลยหันมาทดลองใช้ Dojo ดูบ้าง

วันนี้ทำหน้าจอหนึ่งซึ่งมีการใช้ event กับ dom
ลองเปรียบเทียบกันดูว่า คำสั่งหน้าตาแตกต่างกันแค่ไหน

เริ่มจาก getElementById ก่อน
ใน Prototype เราใช้
$('foo')

ส่วนใน Dojo
dojo.byId('foo')

ใน Prototype เราสามารถ get แบบนี้ได้
var element_array = $('foo','bar','xxx')

ใน Dojo
var element_array = dojo.byIdArray('foo','bar','xxx')


การ attach event เข้ากับ element
ใน prototype
function myFunction() { ... }
Event.observe('foo', 'click', myFunction);
หรือ
Event.observe($('foo'), 'click', myFunction);

ใน Dojo
function myFunction() { ... }
dojo.event.connect(dojo.byId('foo'), 'onclick', myFunction);

จะเห็นว่า prototype จะแปะ "on" ให้กับ event เอง

กรณี detact event
prototype ใช้

Event.stopObserving('foo', 'click', myFunction);

Dojo
dojo.event.disconnect(dojo.byId('foo'))


กรณี Effect
Prototype

new Effect.Fade('foo', {duration: .5});

Dojo
dojo.fx.html.fadeHide(dojo.byId('foo'), 500);


กรณีที่ combine effect โดยมีลำดับก่อนหลัง
Prototype
new Effect.Fade('foo', {queue:'front', duration: .5});
new Effect.Fade('bar', {duration: .5});

ใน Dojo ไม่แน่ใจว่ามีเรื่อง combine effect หรือเปล่า
เพราะเอกสารมันน้อย
แต่สามารถเรียงลำดับโดยใช้ hook function เข้ามาช่วย
dojo.fx.html.fadeHide(dojo.byId('foo'), 500,
function() {
dojo.fx.html.fadeHide(dojo.byId('bar'), 500);
});


feature ที่เกี่ยวกับ Enumeration
Prototype
var ary = ['foo', 'bar'];
var total = 0.0;
ary.each(function(elm) {
total += getValue(elm);
});

Dojo
var ary = ['foo', 'bar'];
var total = 0.0;
dojo.lang.forEach(ary,
function(elm) {
total += getValue(elm);
});


add, remove css class
prototype
Element.addClassName('foo', 'bar');
Element.removeClassName('foo', 'bar');

dojo
dojo.html.addClass(dojo.byId('foo'), 'bar');
dojo.html.removeClass(dojo.byId('foo'), 'bar');


เปรียบเทียบแค่นี้แหล่ะ เพราะหน้าจอแรก ใช้อยู่เท่านี้

Update ไปนั่งไล่ดู code ใหม่แล้ว พบว่า function ส่วนใหญ่รับค่า node เป้น string name ได้
แต่ตัว event.connect นี่ไล่ดู code แล้วมันแปลกๆอยู่ ดูเหมือนว่าต้อง pass เป็น object

Related link from Roti

Wednesday, June 14, 2006

Sue Rubira ชอบงาน painting ของเขา(เธอ) จริงๆ

Related link from Roti

Tuesday, June 13, 2006

retract ใน Drool

อ้างถึงที่เคย post เรื่อง drool ไป

โง่อยู่ตั้งนาน ไม่ยอมอ่านคู่มือให้ดี
feature หนึ่งใน Drool ที่ผมพลาดไปก็คือ
ก็คือ retract(object) ซึ่งตรงข้ามกับ assert(object)

assert ก็คือการส่ง object เข้าไปใน working memory ของ rule engine
ซึ่ง rule engine จะตรวจเงื่อนไขว่าควรจะมีการ trig ให้ rule อะไรทำงานบ้าง
ส่วน retract ก็ตรงกันข้าม ใช้สำหรับล้าง object ออกจาก working memory

ที่นี้ retract เอามาใช้ทำอะไรบ้าง
กรณีแรกเลย ก็คือ กรณีที่ rule conflict กัน
(assert ครั้งเดียว แล้วมีหลาย rule ที่ trig พร้อมๆกัน
และพยายาม update resource ตัวเดียวกัน)
ซึ่งเราต้องใช้ salience เข้ามาช่วย
เพื่อเรียงลำดับว่าอะไรมี priority สูงกว่ากัน

ที่ผมทำผิดไป ก็คือ ผมเรียงลำดับให้ rule ผิด
(ได้ผลลัพท์ถูก แต่ในแง่ของ performance แล้ว
ไม่ถูกต้องอย่างยิ่ง)
ที่ถูกต้อง คือต้องนำเอา retract มาช่วยตัดวงจรไม่ให้ rule ที่เหลือทำงาน
โดยเรียงให้ rule ที่มีความสำคัญสูงสุด มีค่า salience สูงสุด
และเมื่อ rule ทำงานเสร็จ ก็ให้ retract object ออกเสีย

rule "ทุกคนได้ส่วนลด 5%"
salience 0
when
o : Order()
then
o.setPercentDiscount(5.0);
retract(o);
end

rule "ลูกค้าภาคเหนือได้ส่วนลด 7 %"
salience 80
when
c : Customer(region == Customer.NORTH)
o : Order(customer == c)
then
o.setPercentDiscount(7.0);
retract(o);
retract(c);
end

rule "ซื้อเกิน 1500 บาท ด้วยเงินสด ได้ส่วนลด 10 %"
salience 90
when
o : Order(amount >= 1500, payType == Order.CASH)
then
o.setPercentDiscount(10.0);
retract(o);
end

rule "สินค้า p-1 จะไม่ให้ส่วนลด"
when
item : OrderItem(p : product)
eval(p.getProductCode().equals("p-1"))
then
item.setIncludeInTotalDiscount(false);
retract(item);
end


ลำดับของการ assert ก็ต้องเรียงให้ดีด้วย
ไม่งั้น retract อาจจะทำให้ case บาง case ไม่ fire ได้
for (OrderItem item : order.getItems()) {
workingMemory.assertObject(item);
}
workingMemory.assertObject(order.getCustomer());
workingMemory.assertObject(order);

Related link from Roti

Monday, June 12, 2006

Slide with Scheme

ลืมเรื่องนี้ไปเลย
slide presentation ที่ผมแสดงในงาน blognone techday นั้น
เขียนขึ้นด้วย programming language ที่ชื่อ scheme
ซึ่งเป็น lisp dialect หนึ่ง

ว่าจะเขียนอธิบายวิธีใช้ไปหลายทีแล้ว แต่ก็ลืมไปเรื่อย
วันนี้เผอิญอ่านเจอใน Minority Blog
เขามี presentation วิธีเขียน slide ด้วย scheme

สิ่งที่น่าสนใจสำหรับการเขียน slide ด้วย scheme
ก็คือ ด้วยขอบเขตที่ slide พึ่งทำได้ มันไม่เยอะจนเกินไป
ทำให้เราหัดเขีียน scheme ได้โดยไม่หมดแรงไปเสียก่อน

ข้อดีของการหัดเขียน scheme ก็คือมันทำให้เราหัดคิดแบบ functional language,
รู้ว่าเขียนโปรแกรมแบบไม่มี side effect เป็นอย่างไร
ส่วนที่สนุกสุด ก็คงเป็นการ present ออกมาเป็น diagram
เพราะมันไม่ได้เขียนตรงไปตรงมา แบบ Imperative Language

ลองดูตัวอย่าง code

Related link from Roti

Sunday, June 11, 2006

Tapestry4 customize component

วันนี้นั่งเขียน custom component ทั้งวัน
ช่วงแรกๆนี่ฝันร้ายเลย
(ฝันร้ายจริงๆ ไม่ใช่คำเปรียบเปรย
เพราะงีบหลับกลางวันไป โดยในฝันมีแต่
source code ของ tapestry เต็มไปหมด
จนงงเลยว่าอันไหนเป็น source ที่เราเห็นจริงๆ
อันไหนเป็นอันที่จิตนาการเห็นในฝัน
)
โจทย์มีอยู่ว่า ต้องการให้ทำ ajax กรณีที่มี
การเปลี่ยนแปลง ข้อมูลใน textfield
ดูเหมือนง่ายๆ ถ้าใน rails ก็กระดิกนิ้วไม่กี่บรรทัด ก็ได้ ajax แล้ว
  <tr>
<td width="25%">เลขที่บัญชี :</td>
<td colspan='3'><%= text_field 'rec_no', 'firm_acct', :size => 10 %><span id="firm_name"></span>
</td>
</tr>
<%= observe_field('rec_no_firm_acct', :url => {:action => 'firm_entry'}) %>


ส่วน tapestry ก็มี Ajax Library component ที่ชื่อ Tacos
ซึ่งใช้ได้ดีเลยแหล่ะ
แต่ไม่ตรงกับ use case ที่จะใช้ั
ก็เลยเดือนร้อนต้องหาทางเขียน component ขึ้นมาเอง
โดยพยายาม reuse code เก่าของ Tacos ให้มากที่สุด

ความยากของ tapestry component อยู่ที่ต้องเข้าใจ model การทำงานภายใน
ซึ่งมี learning curve ที่สูงใช้ได้เลย
ต้อง debug ไล่ code กันหลายรอบ กว่าจะเห็นภาพว่า
เกิดอะไรขึ้นข้างใน tapestry บ้าง

เอารูป prototype มาให้ดูเล่นๆแล้วกัน
อันนี้ยังไม่ลงเส้นทางที่ต้องไปผ่าน javascript,
ไม่รวมเส้นทางภายในของ tapestry เอง,
กับยังมองไม่เห็นการเชื่อมโยงกับ html ที่เกิดขึ้น
อธิบายไม่ไหว รายละเอียดมันเยอะ

Related link from Roti