เนื้อหานี้มีข้อผิดพลาดทั่วไปส่วนใหญ่ที่ฉันเคยเห็นในโค้ด Java ของบุคคลที่ทำงานกับฉัน การวิเคราะห์แบบคงที่ (เราใช้qulice ) ด้วยเหตุผลที่ชัดเจน ไม่สามารถตรวจพบข้อผิดพลาดดังกล่าวทั้งหมดได้ ซึ่งเป็นสาเหตุที่ฉันตัดสินใจแสดงรายการไว้ที่นี่ ข้อผิดพลาดทั้งหมดนี้เกี่ยวข้องกับการเขียนโปรแกรมเชิงวัตถุโดยทั่วไปและโดยเฉพาะ Java
ชื่อชั้นเรียน
ชั้นเรียนของคุณควรเป็นสิ่ง ที่ เป็นนามธรรมของวัตถุในชีวิตจริงโดยไม่มี " validators " , " controllers " , " managers "ฯลฯ หากชื่อชั้นเรียนของคุณลงท้ายด้วย "-er" แสดงว่าการออกแบบไม่ดี และแน่นอนว่าคลาสตัวช่วยต่อต้านรูปแบบเช่น StringUtils , FileUtilsและ IOUtils ของ Apache เป็นตัวอย่างที่ดีของรูปแบบการออกแบบที่แย่มาก อย่าเพิ่มส่วนต่อท้ายหรือคำนำหน้าเพื่อแยกความแตกต่างระหว่างอินเทอร์เฟซและคลาส ตัวอย่างเช่น ชื่อทั้งหมดนี้แย่มาก: IRecord , IfaceEmployeeหรือ RecordInterface โดยทั่วไป ชื่ออินเทอร์เฟซคือชื่อของออบเจ็กต์ในชีวิตจริง ในขณะที่ชื่อคลาสควรอธิบายรายละเอียดการใช้งาน หากไม่มีสิ่งใดเฉพาะเจาะจงเกี่ยวกับการนำไปใช้งาน ชื่อ " Default ", " Simple " หรืออะไรทำนองนั้นก็จะมีผล ตัวอย่างเช่น:class SimpleUser implements User {}; class DefaultRecord implements Record {}; class Suffixed implements Name {}; class Validated implements Content {};
ชื่อวิธีการ
วิธีการสามารถส่งคืน " บางสิ่ง " หรือส่งคืน " เป็นโมฆะ " หากเมธอดส่งคืนบางสิ่ง ชื่อของมันควรจะอธิบายสิ่งที่จะถูกส่งคืน ตัวอย่างเช่น (อย่าใช้คำนำหน้า " get "):boolean isValid(String name); String content(); int ageOf(File file);
หากส่งคืน "
void " ชื่อควรชี้แจงว่าเมธอดนี้ทำอะไร ตัวอย่างเช่น:
void save(File file); void process(Work work); void append(File file, String line);
มีข้อยกเว้นเพียงข้อเดียวสำหรับกฎนี้ - วิธี ทดสอบ
JUnit มีการอธิบายไว้ด้านล่าง
ชื่อวิธีทดสอบ
ชื่อวิธีการในการทดสอบ JUnit ต้องสร้างเป็นประโยคภาษาอังกฤษโดยไม่มีช่องว่าง วิธีนี้อธิบายได้ง่ายกว่าด้วยตัวอย่าง: สิ่ง/** * HttpRequest can return its content in Unicode. * @throws Exception If test fails */ public void returnsItsContentInUnicode() throws Exception { }
สำคัญคือต้องเริ่มประโยคแรกของ JavaDoc ของคุณด้วยชื่อของคลาสที่คุณกำลังทดสอบตามด้วย “
can ” ดังนั้น ประโยคแรกควรเป็นเหมือนวลี "
someone can do something " เสมอ ชื่อวิธีจะระบุสิ่งเดียวกัน แต่ไม่มีหัวข้อการทดสอบ ถ้าฉันเพิ่มไว้ที่ตอนต้นของชื่อเมธอด ฉันจะได้ประโยคภาษาอังกฤษที่สมบูรณ์ ดังตัวอย่างด้านบน: “
HttpRequest ส่งคืนเนื้อหาในรูปแบบ unicode ” โปรดทราบว่าชื่อวิธีทดสอบไม่ได้ขึ้นต้นด้วย "
can " เฉพาะความคิดเห็น JavaDoc ที่ขึ้นต้นด้วย "
can " นอกจากนี้ ชื่อวิธีการไม่ควรขึ้นต้นด้วยกริยา (
จากผู้แปล: เห็นได้ชัดว่าผู้เขียนหมายถึงอารมณ์ที่จำเป็นของกริยา ) แนวทางปฏิบัติที่ดีคือการระบุว่ามีข้อยกเว้นเกิดขึ้นเมื่อประกาศวิธีทดสอบ
ชื่อตัวแปร
หลีก เลี่ยงชื่อตัวแปรแบบผสม เช่น timeOfDay , firstItemหรือ httpRequest ฉันหมายถึงทั้งตัวแปรคลาสและตัวแปรวิธีการ ชื่อตัวแปรควรยาวพอที่จะหลีกเลี่ยงความคลุมเครือในขอบเขต แต่อย่ายาวเกินไปหากเป็นไปได้ ชื่อต้องเป็นคำนามเอกพจน์หรือพหูพจน์ ตัวอย่างเช่น: บางครั้งอาจมีการขัดแย้งกันระหว่างพารามิเตอร์ตัวสร้างและฟิลด์คลาสหากตัวสร้างเก็บข้อมูลอินพุตไว้ในวัตถุที่สร้างขึ้น ในกรณีนี้ แนะนำให้สร้างคำย่อโดยลบสระออก ตัวอย่าง: ในกรณีส่วนใหญ่ ชื่อตัวแปรที่ดีที่สุดจะเป็นชื่อของคลาสที่เกี่ยวข้อง เพียงแค่ ใช้อักษรตัวพิมพ์ใหญ่แล้วคุณจะไม่เป็นไร อย่างไรก็ตาม อย่าทำเช่นเดียวกันกับประเภทดั้งเดิมเช่นหรือ คุณยังสามารถใช้คำคุณศัพท์ได้เมื่อมีตัวแปรหลายตัวที่มีลักษณะแตกต่างกัน ตัวอย่างเช่น:List
names; void sendThroughProxy(File file, Protocol proto); private File content; public HttpRequest request;
public class Message { private String recipient; public Message(String rcpt) { this.recipient = rcpt; } }
File file; User user; Branch branch;
Integer number
String string
String contact(String left, String right);
คอนสตรัคเตอร์
โดยไม่มีข้อยกเว้น ควรมีตัวสร้างเพียงตัวเดียวเท่านั้นที่เก็บข้อมูลลงในตัวแปรอ็อบเจ็กต์ ตัวสร้างอื่นๆ ทั้งหมดจะต้องเรียกอันนี้ด้วยพารามิเตอร์ที่แตกต่างกัน: public class Server { private String address; public Server(String uri) { this.address = uri; } public Server(URI uri) { this(uri.toString()); } }
ตัวแปรแบบครั้งเดียว
หลีกเลี่ยงตัวแปรที่เกิดครั้งเดียวโดยเสียค่าใช้จ่ายทั้งหมด โดย “ทิ้ง” ฉันหมายถึงตัวแปรที่ใช้ครั้งเดียว เช่นเดียวกับในตัวอย่างนี้:String name = "data.txt"; return new File(name);
ตัวแปรถูกใช้เพียงครั้งเดียว และโค้ดสามารถทำให้ง่ายขึ้นเป็น:
return new File("data.txt");
บางครั้ง ในกรณีที่หายากมาก ซึ่งส่วนใหญ่เนื่องมาจากการจัดรูปแบบที่ดีกว่า - สามารถใช้ตัวแปรแบบครั้งเดียวได้ อย่างไรก็ตาม พยายามหลีกเลี่ยงสถานการณ์ดังกล่าว
ข้อยกเว้น
แน่นอนคุณไม่ควร "กลืน" ข้อยกเว้น ควรโยนให้สูงที่สุด ข้อยกเว้นจากวิธีการส่วนตัวจะต้องได้รับการจัดการจากภายนอก ห้ามใช้ข้อยกเว้นเพื่อควบคุมโฟลว์ รหัสในตัวอย่างไม่ถูกต้อง:int size; try { size = this.fileSize(); } catch (IOException ex) { size = 0; }
จริงๆ แล้วถ้า IOException แจ้งว่า "ดิสก์เต็ม" คุณจะถือว่าขนาดไฟล์เป็นศูนย์แล้วดำเนินการต่อหรือไม่
การเยื้อง
สำหรับการเยื้อง กฎทั่วไปคือวงเล็บต้องสิ้นสุดบรรทัดหรือปิดบนบรรทัดเดียวกัน (ใช้กฎตรงกันข้ามสำหรับวงเล็บปิด) ในตัวอย่างด้านล่าง รหัสไม่ถูกต้องเนื่องจากวงเล็บแรกไม่ได้ปิดอยู่ในบรรทัดเดียวกันและมีอักขระอยู่ข้างหลัง วงเล็บเหลี่ยมที่สองมีปัญหาเดียวกันเนื่องจากมีอักขระอยู่ข้างหน้า และไม่มีวงเล็บเปิดในบรรทัดปัจจุบันfinal File file = new File(directory, "file.txt");
การเยื้องที่ถูกต้องควรมีลักษณะดังนี้:
StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join( Arrays.asList("a", "b") ) ), "separator" );
กฎสำคัญประการที่สองของการเยื้องคือ คุณควรวางให้มากที่สุดเท่าที่จะเป็นไปได้ในหนึ่งบรรทัด - ภายใน 80 อักขระ ตัวอย่างข้างต้นไม่ถูกต้องเนื่องจากสามารถบีบอัดได้:
StringUtils.join( Arrays.asList( "first line", "second line", StringUtils.join(Arrays.asList("a", "b")) ), "separator" );
ค่าคงที่ซ้ำซ้อน
ค่าคงที่คลาสควรใช้เมื่อคุณต้องการแบ่งปันการเข้าถึงข้อมูลระหว่างวิธีการเรียน และข้อมูลนี้เป็นคุณลักษณะ( ! ) ของชั้นเรียนของคุณ อย่าใช้ค่าคงที่แทนสตริงหรือตัวอักษรตัวเลข - การปฏิบัติที่แย่มาก จะทำให้โค้ดเสียหาย ค่าคงที่ (เช่นเดียวกับวัตถุ OOP อื่นๆ) จะต้องมีความหมายในโลกแห่งความเป็นจริง ความหมายของค่าคงที่เหล่านี้ในโลกแห่งความเป็นจริงคืออะไร:class Document { private static final String D_LETTER = "D"; // bad practice private static final String EXTENSION = ".doc"; // good practice }
ข้อผิดพลาดทั่วไปอีกประการหนึ่งคือการใช้ค่าคงที่ในการทดสอบหน่วยเพื่อหลีกเลี่ยงการทำซ้ำค่าสตริง/ตัวเลขในวิธีทดสอบ อย่าทำอย่างนั้น! วิธีการทดสอบแต่ละวิธีจะต้องดำเนินการกับชุดค่าอินพุตของตัวเอง ใช้ข้อความและตัวเลขใหม่ในแต่ละวิธีทดสอบใหม่ การทดสอบมีความเป็นอิสระ เหตุใดพวกเขาจึงควรแบ่งปันค่าคงที่อินพุตเดียวกัน
ทดสอบการเชื่อมต่อข้อมูล
นี่คือตัวอย่างของ hooking ในวิธีทดสอบ:User user = new User("Jeff"); // maybe some other code here MatcherAssert.assertThat(user.name(), Matchers.equalTo("Jeff"))
; ในบรรทัดสุดท้าย เราเชื่อม "
Jeff " ด้วยสตริงลิเทอรัลเดียวกันกับที่ระบุไว้ในบรรทัดแรก ไม่กี่เดือนต่อมา ถ้ามีคนต้องการเปลี่ยนค่าในบรรทัดที่สาม เขา/เธอจะต้องใช้เวลาเพิ่มเติมในการค้นหาว่ามีที่ไหนใช้ "
Jeff " ในวิธีนี้ เพื่อหลีกเลี่ยงไม่ให้ข้อมูลติดขัด คุณควรแนะนำตัวแปร
GO TO FULL VERSION