Group Blog
 
All Blogs
 

Pattern การเช็คข้อมูลบน C#

เวลา Design Code ที่จำเป็นต้องเช็คข้อมูลหลายๆ ส่วน เช่น if (Name.Duplicate) return; อาจจะพบปัญหว่าว่าในการเช็คแต่ละ If นั้นต้องใช้โค้ดซ้ำเพื่อส่ง Error Message หรือทำการจัดการ Error เสียก่อน ซึ่งแต่ก่อนผมออกแบบมาไว้ว่า

if (Name.Duplicate)

{

SomeErrorMethod(SomeArgs);

return;

}

if (ID.Duplicate)

{

SomeErrorMethod(SomeArgs);

return;

}

ซึ่งถ้าทำแบบนี้แล้วเวลากลับมาอ่านโค้ดมันจะไม่ค่อยไหลลื่น คือเวลาเราอ่านถ้าอยากรู้ว่า Error แล้วทำอะไรก็ต้องไปดู Definition ของ SomeErrorMethod ทีนึง ทั้งๆ ที่การแจ้ง Error นั้นอาจจะเป็นของเฉพาะในงานนี้เท่านั้น เวลาเขียนโค้ดให้อ่านง่ายก็ควรจะใส่รวมไว้ในงานนี้ นอกจากนั้นการออกแบบยังงี้ยังทำให้จำนวน private Method โตโดยไม่จำเป็นอีกด้วย

พี่ที่ทำงานเค้าเสนอมาว่าให้ออกแบบโดยใช้ try-catch เข้าช่วยแล้วใช้ Customize Exception เป็นตัวดัก

try

{

if (Name.Duplicate) throw new DataInvalidException(SomeArgs)

if (ID.Duplicate) throw new DataInvalidException(SomeArgs)

}

catch (DataInvalidException ex)

{

// Insert Error Code Here

}

การทำแบบนี้จะทำให้โค้ดของเราสามารถอ่านได้ง่ายขึ้นมาก โดยไม่ต้องมี SomeErrorMethod หลายๆ ตัว ผมถือคติว่าโค้ดที่อ่านง่ายจะต้องอ่านแล้วกระโดดไปมาน้อยที่สุด ไม่ใช่ว่าต้องรวมทุกอย่างใน Method เดียวนะครับ แต่ต้องว่าอ่านแค่ Method เดียวแล้วเข้าใจ Flow การทำงานคร่าวๆ ได้โดยไม่ต้องอ่าน Method ย่อยใดๆ เลยแม้แต่นิดเดียว แต่ Detail อาจจะต้องดู Method ย่อยอีกที




 

Create Date : 30 สิงหาคม 2555    
Last Update : 30 สิงหาคม 2555 21:26:21 น.
Counter : 623 Pageviews.  

ปัญหาตลกๆ ในเรื่อง 32 bit/64 bit

ไม่ได้อัพมานาน วันนี้เจอปัญหาที่แลดูจะน่าตลกมากคือ เรามี 2 Projects อันนึงเป็นงานหลัก อีกอันเป็น DLL Library ที่มา Reference ซึ่งเรื่องตลกคือพอ Compile DLL ออกมาเป็นไฟล์แยก แล้วเอาไปใส่ใน Project แรก โปรแกรมทำงานได้ตามปกติ แต่พอให้ Reference ทั้ง Project เลย มันฟ้อง Error ออกมา

"An attempt was made to load a program with an incorrect format"

ซึ่งก็น่าตลกเพราะการ Reference Project ควรจะปลอดภัยกว่าเอา DLL ตัวเดี่ยวแยก

สรุปปัญหาคือ ปัญหานี้จะเกิดเมื่อ Project หลักมี Target Platform ที่ไม่ตรงกับ DLL เช่นเซ็ตเป็น x86 แต่อีกฝั่งเซ็ตเป็น x64

จริงๆ ปัญหานี้เล็กมาก แต่ผมงงว่าทำไม .NET Framework ถึงสามารถอ้างอิง DLL ที่ Compile แล้วได้หว่า ถ้าปัญหาคือคนละ Platform จริง ก็ควรจะไม่สามารถอ้างอิงได้ทั้งแบบอ้างอิงโปรเจ๊กต์ และอ้างอิง DLL โดยตรง แต่กลายเป็นว่าอ้างอิง DLL โดยตรงได้เฉยเลยซะงั้น ???




 

Create Date : 30 สิงหาคม 2555    
Last Update : 30 สิงหาคม 2555 21:24:59 น.
Counter : 407 Pageviews.  

Javascript Pattern for Gathering Data from Pages & Check consistency

วันนี้ต้องเขียน Javascript เพื่อรวบรวมข้อมูลที่ผู้ใช้ป้อนในแบบฟอร์มของ Web Page เลยพยายามแยกออกมาเป็นฟังก์ชั่นทำงานโดยเฉพาะ

function gatherData() {

.....

return data;

}

แต่ทีนี้นึกขึ้นมาได้ว่า อ้าว แล้วถ้าผู้ใช้ป้อนข้อมูลไม่ครบล่ะ อย่างเช่นปล่อย textbox ที่ควรจะต้องป้อนข้อมูลให้เป็นช่องว่าง เราจะออกแบบยังไงให้ฟังก์ชั่นนี้สามารถบอกได้ด้วยว่าผู้ใช้ป้อนข้อมูลไม่ครบนะ เกิด Error ขึ้นมา แล้ว Error ดังกล่าวคืออะไร

สมัยก่อนตอนยังห่วยๆ อยู่ ผมจะตรวจสอบที่ฝั่งผู้เรียกใช้ เช่น

r=gatherData();

if (r.Name=='') ErrorMessageBox('Error');

ซึ่งวันนี้คิดได้แล้วว่าออกแบบมาห่วย น่าจะมีวิธีการที่ดีกว่าที่จะทำให้ Flow การทำงานทั้งหมดไปรวมอยู่ในฟังก์ชั่นเก็บข้อมูลทีเดียว ไม่ใช่แยกออกมาเป็นเก็บข้อมูลส่วนนึง เช็คข้อมูลอีกส่วนนึง ทั้งๆ ที่การเก็บข้อมูลกับการเช็คความถูกต้องมันก็มี Process เหมือนๆ กัน

เป็นครั้งแรกที่รู้สึกขอบคุณความเป็น Weaked-Type ของ Javascript (ปกติจะเกลียดมากๆ) เลยลองออกแบบให้ฟังก์ชั่นนี้ return object คนละแบบไปเลยเมื่อเกิด Error

 

if ($('#importantCheckbox').attr('checked')) res.someData= 2;    

 else {        

 r = { IsError: true, ErrorMessage: 'Please select criteria type' };         

return r;     

}

(ตั้ง r ไว้แยกกับ return เผื่อมีปัญหาจะได้ breakpoint ได้ง่ายๆ) 

ทีนี้ฟังก์ชั่นที่มาเรียกใช้ก็แทบจะไม่จำเป็นต้องรู้อะไรเลยว่าต้องเช็คข้อมูลยังไง แล้วถ้า Error มันจะเกิดเพราะอะไร ในเมื่อเรามีทั้ง IsError และ ErrorMessage มาให้แล้ว (คล้ายๆ ทำ Exception เองเลยเนอะ) สามารถเช็คข้อมูลได้ง่ายๆ เลย 

r=gatherData();

if (r.IsError) {

ErrorMessageBox(r.ErrorMessage);

return;

}

ถ้าละเอียดขึ้นอาจจะเพิ่ม ErrorID เข้าไปด้วยก็ได้

จริงๆ เป็น Pattern การออกแบบง่ายๆ ที่ระดับเซียนคงคิดกันได้หมดแล้วแหละ (แต่เราพึ่งมาคิด) ส่วนตัวคิดว่าทำให้โค้ดดูอ่านง่ายขึ้นเยอะ




 

Create Date : 30 สิงหาคม 2555    
Last Update : 30 สิงหาคม 2555 21:23:42 น.
Counter : 286 Pageviews.  

ข้อควรจำในการใช้ Enumeration

Enumeration เป็นตัวแปรที่ทำให้ Code เราเข้าใจได้ง่ายขึ้นมาก แต่ถึงแม้ว่ามันจะสะดวกยังไง ก่อนใช้ Enumeration ควรจะมีการออกแบบและคิดให้ถี่ถ้วนด้วย ซึ่งการออกแบบที่ผมเคยผิดพลาดและคาดว่าน่าจะมีคนผิดพลาดบ่อยจะมีดังนี้

- ใช้ Enum แทนตัวเลขที่ติดกัน

โดยปกติเรามักจะประกาศ Enum แต่ละตัวแทนค่าด้วยตัวเลขที่ติดกันเรียงลำดับลงไปเช่น

UserRight = {  None = 0, Admin = 1, User = 2, Guest = 3 }

ซึ่งการออกแบบอย่างนี้จะทำให้มีปัญหาเมื่อในอนาคตเราต้องการแทรกข้อมูลระหว่างกลาง เช่นในตัวอย่างอนาคตถ้าระบบเรารองรับ SuperUser ขึ้นมา ซึ่งสิทธิ์ควรจะอยู่สูงกว่า User แต่ต่ำกว่า Admin ตามลำดับที่ถูก SuperUser ควรจะอยู่ระหว่าง Admin และ User แต่เนื่องจากเราประกาศให้ Admin เป็น 1 และ User เป็น 2 ไปแล้วจึงทำให้ SuperUser ต้องกลายเป็น 4,5 ไปโดยปริยาย ซึ่งตรงนี้ถ้าแค่เพิ่ม SuperUser อย่างเดียวก็ยังอ่านรู้เรื่อง แต่ถ้าในอนาคตเรามีสิทธิ์เป็น 20 กว่าแบบล่ะ จะกลายเป็นว่าสิทธิ์ของเราใน Enum จะเรียงลำดับแบบ "มั่ว" ขึ้นอยู่กับว่าสิทธิ์ไหนเกิดก่อนเกิดหลัง คิดดูละกันว่าในอนาคตผ่านไปอีกปี Enum ของเรากลายเป็น

UserRight = { None=0, Admin=1, User=2, Guest=3, SuperUser=4, Manager=5, Trainee=6, Supervisor=7 .... }

แล้วเอาเวลาเอา Enum ตัวนี้ทำเป็น XML, JSON เพื่อคุยกันล่ะ ลองนึกภาพว่าเรา Debug เว็บอยู่แล้วเห็น 5 โอว ต้องมาเปิดตารางดูกันมันส์เลยว่าคนๆ นี้สิทธิ์ประมาณไหน แทนที่เราจะกะคร่าวๆ ได้ว่าเห้ย 5 มันก็ต้องมีสิทธิ์เหนือกว่า 6 นิดนึงนะ

วิธีการออกแบบที่ดีเราควรจะกำหนดให้ Enum แต่ละตัวมีช่องว่างระหว่างกันเพื่อรองรับเหตุการณ์ในอนาคตครับ เช่น UserRight = { None = 0, Admin = 100, User =200 } ถ้าวันหลังมี SuperUser ก็ให้เป็น 150 ซะก็หมดเรื่อง

- Cast Enum ไปมาระหว่างกันตรงๆ โดยไม่ใช้ switch case

โปรแกรมเมอร์มือใหม่อย่างผมเคยมักง่ายใช้ตัวเลขใน Enum มาแปรหากันตรงๆ เช่น ถ้าผมมี Enum 2 ตัว

Language = { None, C#, Java }; Company={ None, Microsoft, Sun }

ถ้าเนื่องจากเรารู้ว่าทั้งสองตัวมีสมาชิกเท่ากัน แล้วค่าก็เท่ากันด้วย ดังนั้นมือใหม่ (ผมเองก็เคย) ก็มักจะ Cast มันออกมาตรงๆ

LanguageInstance = (Language) Company; 

การเขียนแบบนี้มันก็ทำงานได้แล้วดูรวดเร็วสะอาดด้วยแค่บรรทัดเดียวจบ แถมความหมายก็เข้าใจง่าย เหมือนจะเป็นอะไรที่ดีมากๆ แต่มันจะมีปัญหาเวลาเราแก้ค่า Enum ครับ อย่างวันดีคืนดีเกิดมีโปรแกรมเมอร์คนอื่นเข้ามาแก้ Enum Company เพิ่มบริษัทเข้าไปเยอะๆ ล่ะ บรรทัดนี้ก็จะ Error ทันที

อันนี้ยังไม่เท่าไหร่ ที่ผมเจอคืออยู่ดีๆ มีคนมาเรียงลำดับ Enum ใหม่ (คนเรียงใหม่บอกเราเรียงไม่ดี ความหมายอ่านยาก) ทีนี้ล่ะเกิดการแปลความข้อมูลผิดพลาด ซึ่งกลายเป็นบั๊กฝังลึกลงโปรแกรมทีเดียว ซึ่งถ้าเกิดแบบนี้ขึ้นนี่เราไม่รู้ตัวบางทีอาจเป็นปีๆ เลยทีเดียว ลองนึกถึงแอพพลิเคชั่นแบบสอบถามที่ผู้ใช้กาข้อ 3 แต่ดันบันทึกลงฐานข้อมูลเป็นเลข 2 ดูละกันครับ บั๊กแบบนี้นี่แค่หาเจอก็ยากแล้ว ตามแก้ยิ่งยากกว่า

สิ่งที่ควรทำคือ ให้ใช้ switch-case ในการแปรข้อมูลไปมาระหว่าง Enum ทุกครั้ง เพื่อป้องกันความผิดพลาดลักษณะนี้เสมอ แม้ว่า Enum จะมีค่าเหมือนกันก็ตาม เขียนยาวหน่อย แต่ปลอดภัยกว่าครับ




 

Create Date : 30 สิงหาคม 2555    
Last Update : 30 สิงหาคม 2555 21:22:55 น.
Counter : 1253 Pageviews.  

ปัญหาเรื่องการเขียนเว็บใน IIS

12 ก.ค. 2012

วันนี้มีปัญหาเรื่องการโฮสต์ WCF Service เพื่อ Debug ใน IIS หลังจาก Format เครื่อง ซึ่งคงต้องจำไว้อีกนานว่าการลง IIS ผ่านแผ่นวินโดว์เฉยๆ ไม่ทำให้ Web Application ที่รันบน .NET 4.0 ทำงานได้นะคร้าบ (ถึงแม้ IIS จะให้เราเลือกได้ว่า App pool ดังกล่าวเป็น .NET 4.0 ก็อย่าไปเชื่อนะครับ มันโกหก!! ไม่ได้ลงแต่ดันให้เราเลือกได้เฉยเลย) ซึ่งเราจำเป็นต้องรัน Aspnet_regiis -i เสียก่อนถึงจะลง .NET 4.0 ให้เราจริงๆ ครับ




 

Create Date : 30 สิงหาคม 2555    
Last Update : 30 สิงหาคม 2555 21:20:59 น.
Counter : 757 Pageviews.  

1  2  

Mariel
Location :


[Profile ทั้งหมด]

ให้ทิปเจ้าของ Blog [?]
ฝากข้อความหลังไมค์
Rss Feed
Smember
ผู้ติดตามบล็อก : 1 คน [?]




Friends' blogs
[Add Mariel's blog to your web]
Links
 

 Pantip.com | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.