Saturday, August 24, 2013

รูปแบบการเขียนโค้ด (code)


แม้ว่าแนวทางการเขียนโค้ดจะไม่มีการกำหนดตายตัว  แต่ก็ได้มีแนวทางการตั้งชื่อตัวแปร คลาส หรือ เมธทอด ต่างๆ ที่สร้างโดยมีที่มาจากตัวอย่างปัญหาของการเขียนโค้ดที่ทำให้อ่านเข้าใจยาก ตำแหน่งผิดเพี้ยน โดยวันนี้จะมาเล่าหลักการ 3 หลัก คือ การตั้งชื่อตัวแปร การใช้วรรค/แท็บ และการใช้วงเล็บ

  1. การตั้งชื่อตัวแปร
เนื่องด้วยกฏของการตั้งชื่อสิ่งต่างๆ ในโลกของการโปรแกรมไม่อนุญาตให้มีการเว้นวรรคระหว่างตัวอักษรทำให้ชื่อตัวแปรต้องเป็นกลุ่มตัวอักษรที่ติดกัน เช่น
int extrapayment;
int except_weightunit;
int multiple-string-number;

จากตัวอย่างในบรรทัดแรกจะเห็นได้ว่าหากเรานำคำต่างๆ มาเขียนติดกันเป็นชื่อตัวแปรทำให้เราอ่านแบ่งคำเพื่อเข้าใจชื่อของตัวแปรได้ยากขึ้นเพราะไม่มีสัญลักษณ์อะไรมาคั่นระหว่างคำ  ในบรรทัดที่ 2 และ 3 มีการใช้ '-' และ '_' มาช่วยในการแบ่งระหว่างคำ  สัญลักษณ์เหล่านี้สามารถนำมาใช้ช่วยให้อ่านได้ขึ้นได้แต่มีข้อเสียอยู่ที่สัญลักษณ์พิเศษเหล่านี้มักจะมีความยากในการพิมพ์เพิ่มขึ้น  ทำให้มีแนวคิดในการตั้งชื่อตัวแปรที่นิยมใช้กันเรียกว่า CamelCase (Wiki)
ผู้เขียนเข้าใจว่ามีที่มาจากลักษณะของอูฐที่มีขอที่ชูสูงโดยมีคอที่ยาวลงมายังลำและโหนกที่มีลักษณะสูงต่ำสลับกันไป  แนวคิดนี้ใช้วิธีในการแบ่งคำโดยให้ตัวอักษรแรกของคำหนึ่งคำจะต้องเป็นตัวพิมพ์ใหญ่และใช้ตัวอักษรที่เหลือของคำเป็นพิมพ์เล็กทั้งหมดทำให้เราได้ชื่อตัวแปรที่อ่านง่ายขึ้น ดังตัวอย่าง
int extraPayment;
int exceptWeightUnit;
int multipleStringNumber;
ซึ่งในภาษา Java ได้ให้แนวทางการใช้ CamelCase ไว้คือ
  • ชื่อตัวแปรและเมธทอดให้ใช้ lowerCamelCase เช่น variableName
  • ชื่อคลาสให้ใช้ UpperCamelCase เช่น ThisIsClassA
  • [ยกเว้น]ชื่อของค่าคงที่ให้ใช้ตัวพิมพ์ใหญ่ทั้งหมดและใช้ '_' เพื่อเว้นวรรคระหว่างคำ CONSTANT_VALUE

  1. การใช้วรรค/แท็บ
การเขียนโค้ดให้อ่านง่าย จุดหนึ่งที่ใช้ก็คือการวรรคและการแท็บ  รูปแบบของโค้ดโดยสากลนั้นใช้การวรรคอย่างน้อยหนึ่ง "เคาะ" เพื่อแบ่งรูปแบบของโค้ดต่างๆ เช่น ประเภทเมธทอด[วรรค]ชนิดของการคืนค่า[วรรค]ชื่อเมธทอด เป็นต้น หรืออนุญาตให้ไม่ต้องใช้วรรคระหว่าง ตัวกำหนดค่า เช่น 5+1 number<=3 เป็นต้น ซึ่งรูปแบบของโค้ดสามารถให้เราใช้วรรคมากกว่าหนึ่ง "เคาะ" ได้  พิจารณาตัวอย่างโค้ด
$search = array('a', 'b', 'c', 'd', 'e');
$replacement = array('foo', 'bar', 'baz', 'quux');
$value = 0;
$anothervalue = 1;
$yetanothervalue = 2;
$search      = array('a',   'b',   'c',   'd',   'e');
$replacement = array('foo', 'bar', 'baz', 'quux');
$value           = 0;
$anothervalue    = 1;
$yetanothervalue = 2;

เห็นได้ว่าตัวอย่างที่ 1 มีการใช้วรรคเพียงหนึ่ง "เคาะ" เพียงอย่างเดียวแต่ตัวอย่างที่ 2 มีการใช้วรรคและแท็บหลายครั้งเพื่อทำให้ผู้อ่านโค้ดสามารถอ่านและเปรียบเทียบจำนวนของตัวแปรได้ง่ายมากขึ้น  แต่ก็มีข้อเสียเกิดขึ้นเมื่อมีการเปลี่ยนค่าหรือชื่อตัวแปรเป็นชื่อที่มีตัวอักษรมากกว่าหรือน้อยกว่าทำให้การเว้นวรรค/แท็บที่วางไว้ผิดตำแหน่งไป  หรือผู้แก้ไขมีการตั้งค่าโปรแกรมที่ใช้เขียนโค้ดโดยมีจำนวน "เคาะ" ในการแท็บไม่เท่ากันก็อาจทำให้รูปแบบโค้ดดูผิดเพี้ยนได้
$search      = array('a',   'bbb',   'cc',   'd',   'e');
$r = array('foo', 'bar', 'baz', 'quux');
$value           = 0;
$a    = 1;
$yetanothervalue = 2;

  1. การใช้วงเล็บ
เมื่อสมัยที่เราเรียนเขียนโค้ดถึงบทที่มีการใช้ if else  เรามักจะเจอตัวอย่างโค้ดที่ดูเข้าใจง่ายแบบนี้
if (you.hasAnswer())
{
    you.postAnswer();
}
else
{
    you.doSomething();
}
แต่เมื่อเรามีการใช้งานโปรแกรมเขียนโค้ดที่มีความสามารถสูงๆ ซึ่งมักจะมีระบบจัดวงเล็บให้อัตโนมัติเราก็จะได้ตัวอย่างโค้ด คือ
if (you.hasAnswer()) {
    you.postAnswer();
} else {
    you.doSomething();
}
ตัวอย่างที่ 1 จะมีข้อเสียเมื่อมีการใช้เงื่อนไขหรือการเรียกฟังก์ชันที่ซ้อนกันมากๆ ทำให้การขึ้นบรรทัดใหม่ของวงเล็บกินเนื้อที่บนหน้าจอทำให้เห็นโค้ดได้น้อยลงและจำนวนบรรทัดที่มากขึ้นนี้ทำให้การพิมพ์โค้ดลงในกระดาษจะต้องใช้กระดาษเพิ่มขึ้นหลายหน้า (หลายๆคนคงเคยชินกับข้อเสียนี้ดี) ในตัวอย่างที่ 2 อาจจะทำให้บางคนอ่านเส้นทางของเงื่อนไขยากขึ้นหรือไม่แน่ใจว่าในโค้ดนี้มีการปิดวงเล็บแล้วรึยังซึ่งโปรแกรมเขียนโค้ดในปัจจุบันมีตัวช่วยมากมายที่จะช่วยแสดงขอบเขตของวงเล็บหรือตรวจสอบและแก้ไขวงเล็บที่ขาดหายไปได้อีกด้วย
การใช้วงเล็บนี้ไม่มีจุดกำหนดที่ตายตัวนอกจากความชอบในการใช้งาน  ส่วนตัวผู้เขียนชอบที่จะผสมทั้งสองวิธีโดยขึ้นบรรทัดใหม่หรือเว้นบรรทัดวงเล็บให้กับเมธทอด คลาสหรือเงื่อนไขสำคัญๆ เพื่อให้อ่านง่ายขึ้นดังตัวอย่าง
public void onSensorChanged(SensorEvent event){
   
 if (samplingFilter(sampling, timeStamp)) {
   
  if(now != 0){
   temp++;
   if(temp == nbElement){
    time = timeStamp - now;
    freQ.setText("Current Frequency = " + nbElement * 1000000000 / time + "Hz");
    temp = 0;
   }
  }
  if(temp == 0){
   now = timeStamp;
   temp++;
  }
 }   
}

No comments:

Post a Comment