8. ค้อนทองคำ
ค้อนทองคำเป็นรูปแบบการต่อต้านที่กำหนดโดยความเชื่อมั่นว่าโซลูชันเฉพาะสามารถใช้ได้ในระดับสากล ตัวอย่าง:-
หลังจากพบปัญหาและค้นหารูปแบบสำหรับโซลูชันที่สมบูรณ์แบบแล้ว โปรแกรมเมอร์พยายามยึดรูปแบบนี้ไว้ทุกที่ นำไปใช้กับโครงการในปัจจุบันและอนาคตทั้งหมด แทนที่จะมองหาโซลูชันที่เหมาะสมสำหรับกรณีเฉพาะ
-
นักพัฒนาบางคนเคยสร้างตัวแปรแคชสำหรับสถานการณ์เฉพาะ (เพราะไม่มีสิ่งอื่นใดที่เหมาะสม) ต่อมา ในโครงการถัดไปซึ่งไม่เกี่ยวข้องกับแคชลอจิกพิเศษ พวกเขาใช้ตัวแปรอีกครั้งแทนที่จะใช้ไลบรารีสำเร็จรูป (เช่น Ehcache) ผลที่ตามมาคือบั๊กจำนวนมากและความไม่ลงรอยกัน รวมถึงเวลาและความกังวลที่เสียเปล่าไปมาก
ใครก็ตามสามารถตกหลุมรักรูปแบบการต่อต้านนี้ได้ หากคุณเป็นมือใหม่ คุณอาจไม่มีความรู้เกี่ยวกับรูปแบบการออกแบบ สิ่งนี้อาจทำให้คุณพยายามแก้ปัญหาทั้งหมดด้วยวิธีเดียวที่คุณเชี่ยวชาญ หากเรากำลังพูดถึงมืออาชีพ เราเรียกสิ่งนี้ว่าการเปลี่ยนรูปมืออาชีพหรือการมองแบบเนิร์ด คุณมีรูปแบบการออกแบบที่คุณต้องการ และแทนที่จะใช้รูปแบบที่ถูกต้อง คุณใช้รูปแบบที่คุณชื่นชอบ โดยถือว่ารูปแบบที่ดีในอดีตรับประกันผลลัพธ์เดียวกันในอนาคต
หลุมพรางนี้อาจสร้างผลลัพธ์ที่น่าเศร้ามาก ตั้งแต่การนำไปใช้งานที่ไม่ดี ไม่เสถียร และยากต่อการคงไว้ ไปจนถึงความล้มเหลวโดยสิ้นเชิงของโครงการ เช่นเดียวกับที่ไม่มียาเม็ดเดียวสำหรับทุกโรค ไม่มีรูปแบบการออกแบบเดียวสำหรับทุกโอกาส
9. การเพิ่มประสิทธิภาพก่อนวัยอันควร
การเพิ่มประสิทธิภาพก่อนวัยอันควรเป็นการต่อต้านรูปแบบที่มีชื่อของมันเอง10. สปาเก็ตตี้โค้ด
Spaghetti codeคือ anti-pattern ที่กำหนดโดยโค้ดที่มีโครงสร้างไม่ดี สับสน และเข้าใจยาก ซึ่งมีการแตกสาขาทุกประเภท เช่น การรวมข้อยกเว้น เงื่อนไข และการวนซ้ำ ก่อนหน้านี้ ผู้ดำเนินการ goto เป็นพันธมิตรหลักของการต่อต้านรูปแบบนี้ คำสั่ง Goto ไม่ได้ใช้อีกต่อไป ซึ่งช่วยขจัดปัญหาและปัญหาที่เกี่ยวข้องได้อย่างมีความสุข
public boolean someDifficultMethod(List<String> XMLAttrList) {
...
int prefix = stringPool.getPrefixForQName(elementType);
int elementURI;
try {
if (prefix == -1) {
...
if (elementURI != -1) {
stringPool.setURIForQName(...);
}
} else {
...
if (elementURI == -1) {
...
}
}
} catch (Exception e) {
return false;
}
if (attrIndex != -1) {
int index = attrList.getFirstAttr(attrIndex);
while (index != -1) {
int attName = attrList.getAttrName(index);
if (!stringPool.equalNames(...)){
...
if (attPrefix != namespacesPrefix) {
if (attPrefix == -1) {
...
} else {
if (uri == -1) {
...
}
stringPool.setURIForQName(attName, uri);
...
}
if (elementDepth >= 0) {
...
}
elementDepth++;
if (elementDepth == fElementTypeStack.length) {
...
}
...
return contentSpecType == fCHILDRENSymbol;
}
}
}
}
}
มันดูแย่มากใช่ไหม น่าเสียดาย นี่เป็นรูปแบบการต่อต้านที่พบได้บ่อยที่สุด :( แม้แต่คนที่เขียนโค้ดดังกล่าวก็จะไม่สามารถเข้าใจได้ในอนาคต นักพัฒนาคนอื่นๆ ที่เห็นโค้ดจะคิดว่า "ถ้าได้ผล ก็โอเค — เป็นการดีกว่าที่จะไม่แตะต้องมัน" บ่อยครั้ง วิธีการแรกจะเรียบง่ายและโปร่งใสมาก แต่เมื่อมีการเพิ่มข้อกำหนดใหม่ วิธีการก็จะค่อยๆ ผูกมัดกับข้อความที่มีเงื่อนไขมากขึ้นเรื่อยๆ จนกลายเป็นความเลวร้ายเช่นนี้ หากวิธีการดังกล่าว ปรากฏขึ้น คุณต้องทำการ refactor ทั้งหมดหรืออย่างน้อยในส่วนที่สับสนที่สุด โดยทั่วไป เมื่อจัดกำหนดการโครงการ เวลาจะถูกจัดสรรสำหรับการ refactoring เช่น 30% ของเวลา sprint สำหรับการ refactoring และการทดสอบ แน่นอนว่า สิ่งนี้ถือว่า ที่ไม่รีบร้อน (แต่เมื่อไหร่จะเกิดขึ้น)ที่นี่ .
11. ตัวเลขมหัศจรรย์
ตัวเลขมหัศจรรย์เป็นรูปแบบต่อต้านการใช้ค่าคงที่ทุกชนิดในโปรแกรมโดยไม่มีคำอธิบายวัตถุประสงค์หรือความหมาย นั่นคือโดยทั่วไปแล้วพวกเขาจะตั้งชื่อได้ไม่ดีหรือในกรณีที่รุนแรง จะไม่มีความคิดเห็นอธิบายว่าความคิดเห็นนั้นคืออะไรหรือเพราะเหตุใด เช่นเดียวกับสปาเก็ตตี้โค้ด นี่เป็นหนึ่งในรูปแบบการต่อต้านที่พบได้บ่อยที่สุด ผู้ที่ไม่ได้เขียนโค้ดอาจหรืออาจไม่มีเงื่อนงำเกี่ยวกับตัวเลขมหัศจรรย์หรือวิธีการทำงานของตัวเลขเหล่านี้ (และเมื่อเวลาผ่านไป ผู้เขียนเองก็ไม่สามารถอธิบายได้) เป็นผลให้การเปลี่ยนหรือลบตัวเลขทำให้รหัสหยุดทำงานร่วมกันอย่างน่าอัศจรรย์ ตัวอย่างเช่น36และ73. เพื่อต่อสู้กับรูปแบบการต่อต้านนี้ ฉันขอแนะนำให้ตรวจสอบโค้ด โค้ดของคุณจะต้องได้รับการตรวจสอบโดยนักพัฒนาที่ไม่เกี่ยวข้องกับส่วนที่เกี่ยวข้องของโค้ด ดวงตาของพวกเขาจะสดใสและพวกเขาจะมีคำถาม: นี่คืออะไร และทำไมคุณถึงทำอย่างนั้น? และแน่นอน คุณต้องใช้ชื่ออธิบายหรือแสดงความคิดเห็น12. การเขียนโปรแกรมคัดลอกและวาง
การเขียนโปรแกรมคัดลอกและวางคือการต่อต้านรูปแบบที่โค้ดของผู้อื่นถูกคัดลอกและวางโดยไม่ได้ตั้งใจ ซึ่งอาจส่งผลให้เกิดผลข้างเคียงที่ไม่คาดคิด ตัวอย่างเช่น การคัดลอกและวางวิธีการคำนวณทางคณิตศาสตร์หรืออัลกอริทึมที่ซับซ้อนที่เราไม่เข้าใจอย่างถ่องแท้ อาจใช้ได้ผลกับกรณีเฉพาะของเรา แต่ในบางกรณีอาจนำไปสู่ปัญหาได้ สมมติว่าฉันต้องการวิธีกำหนดจำนวนสูงสุดในอาร์เรย์ ค้นหาทางอินเทอร์เน็ตฉันพบวิธีแก้ปัญหานี้:
public static int max(int[] array) {
int max = 0;
for(int i = 0; i < array.length; i++) {
if (Math.abs(array[i]) > max){
max = array[i];
}
}
return max;
}
เราได้อาร์เรย์ที่มีตัวเลข 3, 6, 1, 4 และ 2 และเมธอดจะส่งกลับ 6 เยี่ยมมาก เก็บไว้เลย! แต่ต่อมาเราได้อาร์เรย์ที่ประกอบด้วย 2.5, -7, 2 และ 3 แล้วผลลัพธ์ของเราคือ -7 และผลลัพธ์นี้ไม่ดี ปัญหาที่นี่คือ Math.abs() คืนค่าสัมบูรณ์ การไม่รู้สิ่งนี้นำไปสู่ความหายนะ แต่ในบางสถานการณ์เท่านั้น หากไม่มีความเข้าใจอย่างลึกซึ้งเกี่ยวกับวิธีแก้ปัญหา มีหลายกรณีที่คุณไม่สามารถยืนยันได้ โค้ดที่คัดลอกอาจไปไกลกว่าโครงสร้างภายในของแอ็พพลิเคชัน ทั้งในเชิงโวหารและในระดับพื้นฐานทางสถาปัตยกรรม รหัสดังกล่าวจะอ่านและบำรุงรักษาได้ยากขึ้น และแน่นอนว่าเราต้องไม่ลืมว่าการคัดลอกโค้ดของผู้อื่นโดยตรงเป็นการลอกเลียนแบบพิเศษ
13. คิดค้นล้อใหม่
การสร้างวงล้อใหม่เป็นการต่อต้านรูปแบบ ซึ่งบางครั้งเรียกว่าการสร้างวงล้อสี่เหลี่ยมขึ้นมาใหม่. โดยพื้นฐานแล้ว เทมเพลตนี้ตรงกันข้ามกับรูปแบบการต่อต้านการคัดลอกและวางที่พิจารณาข้างต้น ในรูปแบบต่อต้านนี้ นักพัฒนาใช้วิธีแก้ปัญหาของตนเองสำหรับปัญหาที่มีวิธีแก้ปัญหาอยู่แล้ว บางครั้งโซลูชันที่มีอยู่เหล่านี้ดีกว่าที่โปรแกรมเมอร์ประดิษฐ์ขึ้น บ่อยครั้งสิ่งนี้นำไปสู่การเสียเวลาและผลผลิตที่ลดลง: โปรแกรมเมอร์อาจไม่พบวิธีแก้ปัญหาเลยหรืออาจพบวิธีแก้ปัญหาที่ห่างไกลจากสิ่งที่ดีที่สุด ที่กล่าวว่า เราไม่สามารถตัดความเป็นไปได้ในการสร้างโซลูชันอิสระได้ เพราะการทำเช่นนั้นเป็นทางตรงสู่การคัดลอกและวางโปรแกรม โปรแกรมเมอร์ควรได้รับคำแนะนำจากงานการเขียนโปรแกรมเฉพาะที่เกิดขึ้นเพื่อแก้ปัญหาอย่างมีประสิทธิภาพ ไม่ว่าจะโดยการใช้โซลูชันสำเร็จรูปหรือโดยการสร้างโซลูชันแบบกำหนดเอง บ่อยมาก, เหตุผลในการใช้รูปแบบต่อต้านนี้เป็นเพียงความเร่งรีบ ผลลัพธ์คือการวิเคราะห์เชิงตื้นของ (ค้นหา) โซลูชันสำเร็จรูป การสร้างวงล้อสี่เหลี่ยมขึ้นใหม่เป็นกรณีที่รูปแบบต่อต้านภายใต้การพิจารณามีผลในทางลบ นั่นคือโครงการต้องการโซลูชันที่กำหนดเองและนักพัฒนาสร้าง แต่ไม่ดี ในขณะเดียวกัน ตัวเลือกที่ดีก็มีอยู่แล้วและคนอื่นๆ ก็ใช้งานได้สำเร็จ สรุป: เสียเวลาไปมาก อันดับแรก เราสร้างสิ่งที่ใช้ไม่ได้ จากนั้นเราพยายามปรับโครงสร้างใหม่ และสุดท้ายเราก็แทนที่ด้วยสิ่งที่มีอยู่แล้ว ตัวอย่างคือการใช้แคชที่คุณกำหนดเองเมื่อมีการใช้งานจำนวนมากอยู่แล้ว ไม่ว่าคุณจะมีพรสวรรค์ในฐานะโปรแกรมเมอร์เพียงใด คุณควรจำไว้ว่าการประดิษฐ์วงล้อสี่เหลี่ยมขึ้นมาใหม่นั้นเป็นการเสียเวลาอย่างน้อยที่สุด และอย่างที่คุณทราบ เวลาเป็นทรัพยากรที่มีค่าที่สุด14. ปัญหาโยโย่
ปัญหาโยโย่คือการต่อต้านรูปแบบที่โครงสร้างของแอปพลิเคชันมีความซับซ้อนมากเกินไปเนื่องจากการแยกส่วนมากเกินไป (ตัวอย่างเช่น ห่วงโซ่การสืบทอดที่แบ่งย่อยมากเกินไป) "ปัญหาโยโย่" เกิดขึ้นเมื่อคุณต้องการทำความเข้าใจโปรแกรมที่มีลำดับชั้นการสืบทอดที่ยาวและซับซ้อน ทำให้เกิดการเรียกใช้เมธอดที่ซ้อนกันลึก เป็นผลให้โปรแกรมเมอร์จำเป็นต้องนำทางระหว่างคลาสและเมธอดต่างๆ มากมายเพื่อตรวจสอบพฤติกรรมของโปรแกรม ชื่อของรูปแบบการต่อต้านนี้มาจากชื่อของของเล่น ตัวอย่างเช่น ลองดูที่ห่วงโซ่การสืบทอดต่อไปนี้: เรามีอินเทอร์เฟซเทคโนโลยี:
public interface Technology {
void turnOn();
}
อินเทอร์เฟซการขนส่งสืบทอดมา:
public interface Transport extends Technology {
boolean fillUp();
}
จากนั้นเรามีอินเทอร์เฟซอื่น GroundTransport:
public interface GroundTransportation extends Transport {
void startMove();
void brake();
}
และจากตรงนั้น เราได้รับคลาสรถยนต์ที่เป็นนามธรรม:
public abstract class Car implements GroundTransportation {
@Override
public boolean fillUp() {
/* some implementation */
return true;
}
@Override
public void turnOn() {
/* some implementation */
}
public boolean openTheDoor() {
/* some implementation */
return true;
}
public abstract void fixCar();
}
ถัดไปคือคลาส Volkswagen ที่เป็นนามธรรม:
public abstract class Volkswagen extends Car {
@Override
public void startMove() {
/* some implementation */
}
@Override
public void brake() {
/* some implementation */
}
}
และสุดท้าย รุ่นเฉพาะ:
public class VolkswagenAmarok extends Volkswagen {
@Override
public void fixCar(){
/* some implementation */
}
}
ห่วงโซ่นี้บังคับให้เราค้นหาคำตอบสำหรับคำถามเช่น:
-
มี กี่วิธี
VolkswagenAmarok
? -
ควรใส่ประเภทใดแทนเครื่องหมายคำถามเพื่อให้ได้นามธรรมสูงสุด:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. ความซับซ้อนโดยบังเอิญ
ความซับซ้อนที่ไม่จำเป็นเป็นรูปแบบต่อต้านซึ่งนำความยุ่งยากที่ไม่จำเป็นมาสู่วิธีแก้ปัญหา
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
switch (type){
case CAR:
jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
case USER:
jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
case FILE:
jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
case PLAN:
jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
case CUSTOMER:
jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
default:
throw new Exception();
}
}
ดังนั้นเรามี enum นี้:
public enum ServiceType {
CAR(),
USER(),
FILE(),
PLAN(),
CUSTOMER()
}
ทุกอย่างดูเหมือนจะง่ายและดี... แต่วิธีอื่นๆ ล่ะ? แน่นอน พวกเขาทั้งหมดจะมีข้อความสั่งจำนวนมากswitch
และการสืบค้นฐานข้อมูลที่เหมือนกันเกือบทั้งหมด ซึ่งจะทำให้ชั้นเรียนของเราซับซ้อนและทำให้ชั้นเรียนของเราขยายใหญ่ขึ้นอย่างมาก ทั้งหมดนี้จะทำให้ง่ายขึ้นได้อย่างไร? มาอัพเกรด enum กันสักหน่อย:
@Getter
@AllArgsConstructor
public enum ServiceType {
CAR("cars_descriptions", "car_id"),
USER("users_descriptions", "user_id"),
FILE("files_descriptions", "file_id"),
PLAN("plans_descriptions", "plan_id"),
CUSTOMER("customers_descriptions", "customer_id");
private String tableName;
private String columnName;
}
ตอนนี้แต่ละประเภทมีชื่อเขตข้อมูลดั้งเดิมของตาราง เป็นผลให้วิธีการสร้างคำอธิบายกลายเป็น:
private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
}
สะดวก เรียบง่าย และกะทัดรัด คุณว่าไหม? ข้อบ่งชี้ของนักพัฒนาที่ดีไม่ได้อยู่ที่ว่าเขาหรือเธอใช้รูปแบบบ่อยเพียงใด แต่ควรสังเกตว่าเขาหรือเธอหลีกเลี่ยงการใช้รูปแบบที่ต่อต้านบ่อยเพียงใด ความไม่รู้คือศัตรูที่ร้ายกาจที่สุด เพราะคุณต้องรู้จักศัตรูด้วยสายตา นั่นคือทั้งหมดที่ฉันมีสำหรับวันนี้ ขอบคุณทุกคน! :)
GO TO FULL VERSION