ดูแล้วรู้สึกว่า โลกปัจจุบัน เรามีแต่สิ่งลวงตาเต็มไปหมด
FluidEffect
เข้าไปที่ portfolio->before/after
Saturday, February 25, 2006
Rails "with_scope"
ใน ActiveRecord มีคำสั่งหนึ่งที่ชื่อ with_scope
คำสั่งนี้ช่วยให้เราจัดการกับ business logic ประเภท
หรือไม่ก็
ลองดู controller code ของตัวอย่างที่ 1
กรณีที่เขียนแบบไม่มี with_scope
ถ้าใช้ with_scope เข้ามาช่วย
ถ้าให้สวยขึ้นอีก ก็ให้แยกส่วนที่ซ้ำๆออกมา
Note: เริ่มพบว่า Rails api เริ่มไม่ consistency เยอะขึ้นเรื่อยๆ เช่น
กรณี find โดยตรงเราสามารถทำแบบนี้ได้
แต่ถ้าใช้ผ่าน with_scope จะ call แบบนี้ไม่ได้
สาเหตุก็คือ ใน method add_conditions ใน file "base.rb" ของ ActiveRecord
มีการใช้ sanitize_sql (method ที่รับผิดชอบการแปลงแบบที่กล่าวข้างบน) เฉพาะกับ
:condition ที่ส่งมากับคำสั่ง find เท่านั้น
ไม่ได้ใช้กับ :condition ใน with_scope ด้วย
ทางแก้ ก็อาจจะ patch base.rb
เพิ่ม sanitize_sql เข้าไปครอบส่วน scope
Note: เข้าไป check source code ของ Rails
มีคน patch ส่วนแก้ไขเข้าไปแล้ว อยู่ใน change set [3379]
คำสั่งนี้ช่วยให้เราจัดการกับ business logic ประเภท
user A ที่สังกัดหน่วยงาน 1001 เมื่อ login เข้ามาแล้ว
สามารถ query ข้อมูลได้เฉพาะข้อมูลของหน่วยงาน 1001 เท่านั้น
และเมื่อสร้าง transaction,
transaction นั้นจะมีรหัสหน่วยงานที่รับผิดชอบเป็น 1001
หรือไม่ก็
User B มี authorize แบบ Regulator
ดังนั้นจึงสามารถ grant สิทธิให้กับเฉพาะ user
ที่สังกัดอยู่ภายใต้ Company ที่ user B ดูแลอยู่
ลองดู controller code ของตัวอย่างที่ 1
กรณีที่เขียนแบบไม่มี with_scope
def list
@txs = Tx.find(:all,
:conditions =>
["organize_id = ?", session[:user].organize_id])
end
def create
...
# tx ที่สร้างจะสังกัดหน่วยงาน ตามหน่วยงานของ user
tx.organize_id = session[:user].organize_id
...
tx.save
...
end
ถ้าใช้ with_scope เข้ามาช่วย
def list
Tx.with_scope(:condition => "organize_id = #{session[:user].organize_id}") do
@txs = tx.find(:all)
end
end
def create
Tx.with_scope(:create => {:organize_id = session[:user].organize_id}) do
...
Tx.save
end
end
ถ้าให้สวยขึ้นอีก ก็ให้แยกส่วนที่ซ้ำๆออกมา
protected
def org_scope
{
:find => {:condition => "organize_id = #{session[:user].organize_id}",
:create => {:organize_id = session[:user].organize_id}
}
end
public
def list
Tx.with_scope(org_scope) do
Tx.find(:all)
end
end
def create
Tx.with_scope(org_scope) do
...
end
end
Note: เริ่มพบว่า Rails api เริ่มไม่ consistency เยอะขึ้นเรื่อยๆ เช่น
กรณี find โดยตรงเราสามารถทำแบบนี้ได้
@txs = Tx.find(:all,
:conditions =>
["organize_id = ?", @org_id])
แต่ถ้าใช้ผ่าน with_scope จะ call แบบนี้ไม่ได้
Tx.with_scope(:find =>
{:conditions =>
["organize_id = ?", @org_id]}) do
Tx.find(:all)
end
สาเหตุก็คือ ใน method add_conditions ใน file "base.rb" ของ ActiveRecord
มีการใช้ sanitize_sql (method ที่รับผิดชอบการแปลงแบบที่กล่าวข้างบน) เฉพาะกับ
:condition ที่ส่งมากับคำสั่ง find เท่านั้น
ไม่ได้ใช้กับ :condition ใน with_scope ด้วย
940 def add_conditions!(sql, conditions)
941 puts "add_conditions #{sql}, #{conditions}"
942 segments = [scope(:find, :conditions)]
943 segments << sanitize_sql(conditions) unless conditions.nil?
944 segments << type_condition unless descends_from_active_record?
945 segments.compact!
946 sql << "WHERE (#{segments.join(") AND (")}) " unless segments.empty?
947 end
ทางแก้ ก็อาจจะ patch base.rb
เพิ่ม sanitize_sql เข้าไปครอบส่วน scope
940 def add_conditions!(sql, conditions)
941 puts "add_conditions #{sql}, #{conditions}"
942 segments = [sanitize_sql(scope(:find, :conditions))]
943 segments << sanitize_sql(conditions) unless conditions.nil?
944 segments << type_condition unless descends_from_active_record?
945 segments.compact!
946 sql << "WHERE (#{segments.join(") AND (")}) " unless segments.empty?
947 end
Note: เข้าไป check source code ของ Rails
มีคน patch ส่วนแก้ไขเข้าไปแล้ว อยู่ใน change set [3379]
Related link from Roti
Wednesday, February 22, 2006
Testing with Hansel
Hansel คือ code coverage ตัวหนึ่ง
จุดที่ผมชอบ ก็คือ วิธีที่มัน integrate กับ JUnit ซึ่งดูเรียบง่ายดี
ลองดูตัวอย่าง
ทดลองเขียน Collection ขึ้นมาอันหนึ่ง ที่เก็บ integer
โดย item ใน collection จะเรียงลำดับจากน้อยไปมากเสมอ
เขียน JUnit Testcase
ทดลอง run ดู ก็จะพบแถบเขียวสวยงาม
ที่นี้ลองใส่ Hansel เข้าไป
โดยการเพิ่ม method นี้ลงไปใน test case
ทดลอง run ใหม่
จะเห็น message error ว่า
ไปไล่โปรแกรมแล้ว จะพบที่ผิดตัวเบ้อเริ่มเลย
บรรทัดที่ 20 เป็นบรรทัดที่ตกค้างจากการที่เขียน code โดยไม่ได้วางแผนมาก่อน
สามารถตัดทิ้งออกไปได้ทั้งยวงเลย
จะเห็นว่า Hansel เข้ามาช่วยอุดจุดอ่อน
ของ Programer ที่ไม่ชอบวางแผน ชอบเขียนโปรแกรมไป-คิดไป-แก้ไป
(แก้ไปแก้มา จนงงเอง) ได้เป็นอย่างดี
หลักการทำงานของ Hansel ก็คือ มันจะทำการ modify class file ที่เราต้องการ test
โดยใช้ BCEL (Byte Code Engineering Library)
ทำการใส่ probe เข้าไปตามบรรทัดต่างๆ แล้ว check ดูว่ามีการเรียกใช้ probe เหล่านั้นหรือไม่
การใส่ probe ของ Hansel ก็ไม่ได้ใส่ดะไปทุก statement นะ
มีการเลือกใส่เฉพาะ statement ที่เป็น branch เท่านั้น
จุดที่ผมชอบ ก็คือ วิธีที่มัน integrate กับ JUnit ซึ่งดูเรียบง่ายดี
ลองดูตัวอย่าง
ทดลองเขียน Collection ขึ้นมาอันหนึ่ง ที่เก็บ integer
โดย item ใน collection จะเรียงลำดับจากน้อยไปมากเสมอ
public class OrderList {
private ArrayList bag;
public OrderList() {
bag = new ArrayList();
}
public void add(int value) {
int size = bag.size();
boolean found = false;
for (int i = 0; i < size; i++) {
Integer elm = (Integer) bag.get(i);
if (value < elm.intValue()) {
if (i == size -1) {
bag.add(new Integer(value));
} else {
bag.add(i, new Integer(value));
}
found = true;
break;
}
}
if (! found) {
bag.add(new Integer(value));
}
}
public int first() {
return ((Integer) bag.get(0)).intValue();
}
public int last() {
return ((Integer) bag.get(bag.size() - 1)).intValue();
}
}
เขียน JUnit Testcase
public class TestOrderList extends TestCase {
/*
* Test method for 'util.OrderList.first()'
*/
public void testFirst() {
OrderList l = new OrderList();
l.add(6);
l.add(9);
l.add(1);
assertEquals(1, l.first());
}
/*
* Test method for 'util.OrderList.last()'
*/
public void testLast() {
OrderList l = new OrderList();
l.add(6);
l.add(9);
l.add(1);
assertEquals(9, l.last());
}
}
ทดลอง run ดู ก็จะพบแถบเขียวสวยงาม
ที่นี้ลองใส่ Hansel เข้าไป
โดยการเพิ่ม method นี้ลงไปใน test case
public static Test suite() {
return new CoverageDecorator(TestOrderList.class,
new Class[] {OrderList.class});
}
ทดลอง run ใหม่
จะเห็น message error ว่า
Coverage failure: Branch not completely covered. Condition 'i == size - 1' is not fulfilled.
at util.OrderList.add(OrderList.java:20)
ไปไล่โปรแกรมแล้ว จะพบที่ผิดตัวเบ้อเริ่มเลย
บรรทัดที่ 20 เป็นบรรทัดที่ตกค้างจากการที่เขียน code โดยไม่ได้วางแผนมาก่อน
สามารถตัดทิ้งออกไปได้ทั้งยวงเลย
จะเห็นว่า Hansel เข้ามาช่วยอุดจุดอ่อน
ของ Programer ที่ไม่ชอบวางแผน ชอบเขียนโปรแกรมไป-คิดไป-แก้ไป
(แก้ไปแก้มา จนงงเอง) ได้เป็นอย่างดี
หลักการทำงานของ Hansel ก็คือ มันจะทำการ modify class file ที่เราต้องการ test
โดยใช้ BCEL (Byte Code Engineering Library)
ทำการใส่ probe เข้าไปตามบรรทัดต่างๆ แล้ว check ดูว่ามีการเรียกใช้ probe เหล่านั้นหรือไม่
การใส่ probe ของ Hansel ก็ไม่ได้ใส่ดะไปทุก statement นะ
มีการเลือกใส่เฉพาะ statement ที่เป็น branch เท่านั้น
Related link from Roti
Tuesday, February 21, 2006
Sea of Lies
วันนี้ดูสารคดีเรื่องเครื่องบินของสายการบิน iran air ที่ถูกยิงตกโดยเรือรบสหรัฐ เมื่อวันที่ 3 กรกฏาคม 1988
ผู้โดยสารและลูกเรือเสียชีวิตไป 290 คน
สาเหตุเกิดจากความผิดผลาดของลูกเรือและกัปตัน
ในการจำแนกระหว่างเครื่องบิน F14 กับ airbus
รวมทั้งอาการ panic ของลูกเรือบางคน
โดยที่ระหว่างที่ยิง เรือรบสหรัฐกำลังอยู่ในน่านน้ำอิหร่านอีกด้วย
เมื่อเรือกลับถึงอเมริกา ก็ได้รับการต้อนรับเยี่ยงวีรบุรุษที่กลับจากสงคราม
ลูกเรือทั้งหมดได้รับ Combat-action ribbons
commander ผู้ควบคุมการต่อสู้ทางอากาศ ได้รับ navy 's Commendation Medal
(for heroic achievement, "ability to maintain his poise and confidence under fire",
or his ability to "quickly and precisely complete the firing procedure"")
แน่นอนกัปตันต้องถูกขึ้นศาลทหาร
ผลการสอบสวน ถือว่าปฎิบัติโดยชอบแล้ว (justifiable self-defense)
อ่านเหตุการณ์ทั้งหมด
Sea of Lies
ปล. สำหรับเติือนสติ ผู้ที่ชอบ Hero แบบในหนัง hollywood
และถูกสะกดจิตว่า ทหารอเมริกันมันเก่งแบบในหนัง
ผู้โดยสารและลูกเรือเสียชีวิตไป 290 คน
สาเหตุเกิดจากความผิดผลาดของลูกเรือและกัปตัน
ในการจำแนกระหว่างเครื่องบิน F14 กับ airbus
"Identify, Friend or Foe?" query, he received a different response: military aircraft. Rogers' decision to fire was made while under the impression that the query was correct--in fact, Anderson had forgotten to reset the system after the first query, and the response he received was probably from a fighter plane on the runway back at Bandar Abbas.
รวมทั้งอาการ panic ของลูกเรือบางคน
Then something happened that psychologists call "scenario fulfillment" - you see what you expect. Petty Officers Anderson and Leach both began singing out that the aircraft, now definitively tagged on the big screen as an F-14, was descending and picking up speed. The tapes of the CIC's data later showed no such thing. Anderson's screen showed that the plane was travelling 380 knots at 12,000 feet and climbing. Yet Anderson was shouting out that the speed was 455 knots, the altitude 7,800 feet and descending.
โดยที่ระหว่างที่ยิง เรือรบสหรัฐกำลังอยู่ในน่านน้ำอิหร่านอีกด้วย
เมื่อเรือกลับถึงอเมริกา ก็ได้รับการต้อนรับเยี่ยงวีรบุรุษที่กลับจากสงคราม
ลูกเรือทั้งหมดได้รับ Combat-action ribbons
commander ผู้ควบคุมการต่อสู้ทางอากาศ ได้รับ navy 's Commendation Medal
(for heroic achievement, "ability to maintain his poise and confidence under fire",
or his ability to "quickly and precisely complete the firing procedure"")
แน่นอนกัปตันต้องถูกขึ้นศาลทหาร
ผลการสอบสวน ถือว่าปฎิบัติโดยชอบแล้ว (justifiable self-defense)
อ่านเหตุการณ์ทั้งหมด
Sea of Lies
ปล. สำหรับเติือนสติ ผู้ที่ชอบ Hero แบบในหนัง hollywood
และถูกสะกดจิตว่า ทหารอเมริกันมันเก่งแบบในหนัง
Related link from Roti
Selenium on Rails
ดู demo ของการ integrate
Selenium กับ Rails ได้ที่นี่
Show don't Tell
ช่วงนี้ผมเริ่มใช้ selenium กับ java project แล้ว
พอมาดูการใช้กับ Rails แล้ว
รู้สึกว่ามัน integrate เข้ากับ Rails ได้ดีมากเลย
(ไม่ว่าจะเป็นการเก็บ test script ไว้ใต้ directory test,
การใช้ script/generate เข้ามาสร้าง stub,
การใช้ rake test,
การใช้ ruby selenium script)
Selenium กับ Rails ได้ที่นี่
Show don't Tell
In the demo I create a new Rails project, install Selenium on Rails, create a test case using Selenium IDE, create another in RSelenese, and run all the test as a Rake task.
ช่วงนี้ผมเริ่มใช้ selenium กับ java project แล้ว
พอมาดูการใช้กับ Rails แล้ว
รู้สึกว่ามัน integrate เข้ากับ Rails ได้ดีมากเลย
(ไม่ว่าจะเป็นการเก็บ test script ไว้ใต้ directory test,
การใช้ script/generate เข้ามาสร้าง stub,
การใช้ rake test,
การใช้ ruby selenium script)
Related link from Roti
จบ trip จักรยาน
จบ trip จักรยานครั้งนี้ ด้วยความรู้สึกยากจะบรรยาย
ความรู้สึกเหมือนได้สัมผัสทั้งสวรรค์ และ นรก คละเคล้ากันไป
เส้นทางที่ขี่คราวนี้ อยู่ในจังหวัดน่านจังหวัดเดียว
ด้วยความไม่ฟิตของร่างกาย
(ไม่ว่าจะเป็นความแข็งแรงของหัวใจ หรือความแข็งแรงของกล้ามเนื้อ)
การขี่จักรยานขึ้นเขายาวๆ บวกกับ แสงแดดร้องเปรี้ยงช่วงบ่าย
(แดดในที่สูงมันร้อนมากเลย)
เป็นการตกนรกแบบสุดทนจริงๆ
การควบคุมจิตใจในช่วงนั้น
ใช้หลักยึดอยู่ 2 ประการ คือ
ส่วนสวรรค์ จะมาในช่วงขาลงจากยอดเขา
ลมที่พัดเข้าใส่หน้า
ความเร็วที่พุ่งลงไป
ความปิติ ที่เกิดจากการผ่านอุปสรรคมาได้
อันนี้แหล่ะช่วงเวลาสั้นๆที่สัมผัสสวรรค์
(แน่นอน เมื่อลงไปสุดทางแล้ว ก็ต้องเจอนรกต่อ)
Note:
ความรู้สึกเหมือนได้สัมผัสทั้งสวรรค์ และ นรก คละเคล้ากันไป
เส้นทางที่ขี่คราวนี้ อยู่ในจังหวัดน่านจังหวัดเดียว
ด้วยความไม่ฟิตของร่างกาย
(ไม่ว่าจะเป็นความแข็งแรงของหัวใจ หรือความแข็งแรงของกล้ามเนื้อ)
การขี่จักรยานขึ้นเขายาวๆ บวกกับ แสงแดดร้องเปรี้ยงช่วงบ่าย
(แดดในที่สูงมันร้อนมากเลย)
เป็นการตกนรกแบบสุดทนจริงๆ
การควบคุมจิตใจในช่วงนั้น
ใช้หลักยึดอยู่ 2 ประการ คือ
- ตั้งเป้าหมายระยะสั้น
ในใจจะนึก "ปั่นอีก 10 ครั้งแล้วค่อยพัก"
พอครบ 10 ครั้ง ก็เริ่มตั้งเป้าใหม่, ขออีก 10 ครั้งน่า
ทำเช่นนี้ไปเรื่อยๆ จนกว่าจะถึงยอดเขา - ควบคุมลมหายใจ และกำหนดจิตให้เป็นสมาธิ
ตอนนี้เราเหนื่อยมากๆ การใช้แรงของเรา มักจะสะเปะสะปะ
การควบคุมลมหายใจ และทำสมาธิกับลมหายใจเข้าออก
จะทำให้เราควบคุมการเคลื่อนไหวและการออกแรงได้ดีขึ้น
ทำให้ไม่มีแรงที่เสียไปอย่างเปล่าๆ (เช่น การเกร็งกล้ามเนื้อที่ไม่มีประโยชน์ต่อการปั่น หรือการออกแรงมากเกินไป)
นอกจากนั้นการมีสมาธิ ยังช่วยไม่ให้จิตของเราไปหมกหมุ่นกับอาการเหนื่อย จนเกินไป
ส่วนสวรรค์ จะมาในช่วงขาลงจากยอดเขา
ลมที่พัดเข้าใส่หน้า
ความเร็วที่พุ่งลงไป
ความปิติ ที่เกิดจากการผ่านอุปสรรคมาได้
อันนี้แหล่ะช่วงเวลาสั้นๆที่สัมผัสสวรรค์
(แน่นอน เมื่อลงไปสุดทางแล้ว ก็ต้องเจอนรกต่อ)
Note:
- ช่วงเวลาที่สุข มักจะน้อยกว่า ช่วงเวลาที่ทุกข์ เสมอ
- พื้นที่ 75% ของจังหวัดน่าน เป็นภูเขา
Related link from Roti
Monday, February 20, 2006
Visualizing Regular Expression
อ่านวิธีการที่เขา implement
น่าสนใจทีเดียว
Note: เขาใช้ OpenLazlo implement ด้วย
อ่านวิธีการที่เขา implement
น่าสนใจทีเดียว
Note: เขาใช้ OpenLazlo implement ด้วย
Related link from Roti
Subscribe to:
Posts (Atom)