blog วันนี้เกิดขึ้นจากความอัดอั้นตันใจนิดหน่อย คือเรื่องมันมีอยู่ว่าผมดันไปมีความเห็นไม่ตรงกับหัวหน้านิดหน่อยในเรื่องของการเขียนโค๊ด โดยโค๊ดตัวที่มีปัญหาก็คือ
if codeinlist(input-a, "AB,CD") and
codeinlist(input-b, "01,02,03,04,05")
then
output = input-a + input-b
else
output = input-a
โค๊ดข้างบนไม่ใช่โค๊ดจริง เพราะเดี๋ยวผมโดนฟ้องจะซวยเอา โจทย์คือ ไอ้ AB05 เป็น output ที่ไม่ถูกต้อง แต่ CD05 ใช้ได้นะ
วิธีที่ผมเสนอไปก็คือ งี้ …
if input-a = "CD" and input-b = "05"
then
output = "CD05"
else if codeinlist(input-a, "AB,CD") and
codeinlist(input-b, "01,02,03,04")
then
output = input-a + input-b
else
output = input-a
โดนด่าเปิงเลยครับ 555 คือพี่เขามองว่าผม hard code น่ะ พี่เขาว่างี้ดีกว่า
if (codeinlist(input-a, "AB,CD") and
codeinlist(input-b, "01,02,03,04"))
or (input-a = "CD" and input-b = "05"
then
output = input-a + input-b
else
output = input-a
คือจริง ๆ ทั้งสองอย่างมีข้อดีต่างกัน อันของผมจะอ่านง่ายกว่าเพราะว่าผมแยกเคสกรณี input-b เป็น 05 ออกมาเป็นอีกเคสนึง ส่วนอันล่างเองโค๊ดจะไม่ซ้ำซ้อนและดูไม่เหมือน hard code แต่ว่าเป็นเงื่อนไขแบบ 2 ระดับ 2 เงื่อนไขซึ่งจะอ่านยากขึ้นนิดนึง
แต่ถ้าถามว่าแบบไหนดีที่สุด ผมเชื่อว่า แบบนี้ครับ
if (input-a = "AB" and
codeinlist(input-b, "01,02,03,04"))
or (input-a = "CD" and
codeinlist(input-b, "01,02,03,04,05"))
then
output = input-a + input-b
else
output = input-a
เสียดายว่าผมปิดงานไปแล้วไม่งั้นจะไปตามแก้ให้เป็นแบบนี้ แต่จริง ๆ นะ ผมคิดว่าแยกมันออกมาเป็นคนละเคสกันจะทำให้อ่านง่ายขึ้นไปอีก
if (input-a = "AB" and
codeinlist(input-b, "01,02,03,04"))
then
output = input-a + input-b
else if input-a = "CD" and
codeinlist(input-b, "01,02,03,04,05")
then
output = input-a + input-b
else
output = input-a
ถามว่าทำไมผมถึงชอบอันล่างสุด คือตอบก็คือ ในส่วนของประโยคเงื่อนไขมันมีแค่ระดับเดียวครับ นี่โชคดีว่าภาษาที่ใช้ใช้คีย์เวิร์ด and กับ or ผมถึงเขียนแบบนี้ได้ ถ้าผมเขียนพวกภาษา C เนี่ยมันจะเป็นสัญลักษณ์ตีกันมั่วไปหมด
เผื่อนึกภาพไม่ออก
if ((inputA == "AB" &&
codeinlist(inputB, "01,02,03,04")) ||
(inputA == "CD" &&
codeinlist(input-b, "01,02,03,04,05")))
{
output = inputA + inputB;
}
else
{
output = inputA;
}
คำถาม … ผมใส่วงเล็บครบมั้ยครับ ?
แต่พอแยกออกมามันก็จะเกิดความซ้ำซ้อนเกิดขึ้น ส่วนตัวผมคิดว่าถ้า statement ข้างใน then มันมีแค่บรรทัดเดียวย่อ ๆ นี่ซ้ำซ้อนกันบ้างอาจจะทำให้อ่านง่ายขึ้นครับ ถ้ายาวก็แยกออกมาเป็นอีกฟังก์ชั่นก็ได้
ผมก็จะสรุปเป็นเทคนิคส่วนตัวที่ผมใช้นะครับ คือ ถ้าเกิดว่า ในประโยคเงื่อนไขของ if statement นั้นเป็นประโยคย่อย ๆ หลาย ๆ อันที่เชื่อมกันด้วย หรือ (or) ผมจะแยกมันออกมาเป็นหลาย ๆ if แทนโดยที่ข้างในแต่ละประโยคก็เหมือนกัน และถ้ามันซับซ้อนมาก ๆ ก็รีแฟคเตอร์มันออกมาเป็นฟังก์ชั่นด้วย
เช่น สมมติว่าแต่ละ statement มันซับซ้อนประมาณนึงนะครับ
if ((statement_A) || (statement_B) || (statement_C)){
doSomething();
}
ผมก็จะทำแบบนี้แทน
if (statement_A) doSomething();
else if(statement_B) doSomething();
else if(statement_C) doSomething();
เนี่ย ซ้ำกันไปเลย
ประโยคที่เชื่อมด้วย or เนี่ย หลาย ๆ ครั้งอาจจะถูกแยกเพราะว่าพอใช้ ๆ ไปเงื่อนไขมันเปลี่ยน ถ้าเราแยกซะตั้งแต่แรกไปเลยก็อาจจะทำให้ไม่ต้องมานั่งแยกภายหลังด้วยครับ
ส่วนประโยคเงื่อนไขที่เชื่อมด้วย และ (and) ผมจะใช้ if ซ้อนใน if หลาย ๆ ชั้นลงไปเรื่อย ๆ แทนครับ เช่น
if ((statement_A) && (statement_B) && (statement_C)){
doSomething();
}
ผมก็จะทำแบบนี้แทน
if (statement_A) {
if(statement_B) {
if(statement_C){
doSomething();
}
}
}
ทั้งสองวิธีตั้งอยู่บนพื้นที่ฐานที่ว่า ประโยคเงื่อนไขไม่ได้ยาวมาก ไอ้ประเภทมี 7-8 เงื่อนไข 4-5 ระดับเนี่ยใช้ไม่ได้นะครับ เขียนแบบนี้เละตายเลย ถ้าเป็นกรณีนี้แนะนำให้ refactor ตัวประโยคเงื่อนไขออกเป็นอีกฟังก์ชั่นนึงแทนไปเลยดีกว่าครับ
ที่สำคัญอีกอย่างก็คือมันก็มี trade-off ครับ โค๊ดอาจจะดูง่ายขึ้น พลาดยากขึ้น แต่ว่าอาจจะมีข้อเสียอื่น ๆ อย่างการซ้ำซ้อน หรือมี branch เยอะ ก็ต้องชั่งน้ำหนักให้ดีก่อนตัดสินใจว่าจะใช้วิธีไหนนะครับ
โปรแกรมเมอร์ C++ และผู้นิยมดนตรี