
8. Gintong martilyo
Ang ginintuang martilyo ay isang anti-pattern na tinukoy ng kumpiyansa na ang isang partikular na solusyon ay nalalapat sa pangkalahatan. Mga halimbawa:-
Matapos makatagpo ng isang problema at makahanap ng isang pattern para sa perpektong solusyon, sinusubukan ng isang programmer na ilagay ang pattern na ito sa lahat ng dako, ilapat ito sa kasalukuyan at lahat ng mga proyekto sa hinaharap, sa halip na maghanap ng mga naaangkop na solusyon para sa mga partikular na kaso.
-
Ang ilang mga developer ay minsang lumikha ng kanilang sariling variant ng isang cache para sa isang partikular na sitwasyon (dahil wala nang iba pa ang angkop). Nang maglaon, sa susunod na proyekto na walang espesyal na lohika ng cache, muli nilang ginamit ang kanilang variant sa halip na gumamit ng mga handa na aklatan (halimbawa, Ehcache). Ang resulta ay isang grupo ng mga bug at hindi pagkakatugma, pati na rin ang maraming nasayang na oras at pinirito na nerbiyos.
Kahit sino ay maaaring mahulog sa anti-pattern na ito. Kung ikaw ay isang baguhan, maaaring wala kang kaalaman tungkol sa mga pattern ng disenyo. Ito ay maaaring humantong sa iyo upang subukang lutasin ang lahat ng mga problema sa isang paraan na iyong pinagkadalubhasaan. Kung ang pinag-uusapan natin ay tungkol sa mga propesyonal, kung gayon tinatawag natin itong propesyonal na pagpapapangit o nerdview. Mayroon kang sariling ginustong mga pattern ng disenyo, at sa halip na gamitin ang tama, ginagamit mo ang iyong paborito, sa pag-aakalang ang isang mahusay na akma sa nakaraan ay ginagarantiyahan ang parehong resulta sa hinaharap.
Ang pitfall na ito ay maaaring magbunga ng napakalungkot na resulta — mula sa isang masama, hindi matatag, at mahirap na mapanatili ang pagpapatupad hanggang sa isang kumpletong pagkabigo ng proyekto. Kung paanong walang isang tableta para sa lahat ng mga sakit, walang isang pattern ng disenyo para sa lahat ng okasyon.
9. Napaaga ang pag-optimize
Ang premature optimization ay isang anti-pattern na ang pangalan ay nagsasalita para sa sarili nito.10. Spaghetti code
Ang spaghetti code ay isang anti-pattern na tinukoy ng code na hindi maganda ang pagkakaayos, nakakalito, at mahirap unawain, na naglalaman ng lahat ng uri ng pagsasanga, gaya ng mga pagbubukod sa pambalot, kundisyon, at mga loop. Dati, ang goto operator ang pangunahing kaalyado nitong anti-pattern. Ang mga pahayag ng Goto ay hindi na talaga ginagamit, na masayang nag-aalis ng ilang nauugnay na paghihirap at problema.
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;
}
}
}
}
}
Mukhang kakila-kilabot, hindi ba? Sa kasamaang palad, ito ang pinakakaraniwang anti-pattern :( Kahit na ang taong nagsusulat ng naturang code ay hindi mauunawaan ito sa hinaharap. Iisipin ng ibang mga developer na nakakakita ng code, "Well, kung ito ay gumagana, pagkatapos ay okay — mas mabuting huwag mo itong hawakan". Kadalasan, ang isang pamamaraan ay sa simula ay simple at napakalinaw, ngunit habang ang mga bagong kinakailangan ay idinagdag, ang pamamaraan ay unti-unting nababalot ng mas maraming kondisyonal na mga pahayag, na ginagawa itong isang napakapangit na tulad nito. Kung ang gayong pamamaraan lilitaw, kailangan mong i-refactor ito nang buo o hindi bababa sa pinakanakalilito na mga bahagi. Kadalasan, kapag nag-iiskedyul ng isang proyekto, ang oras ay inilalaan para sa refactoring, halimbawa, 30% ng oras ng sprint ay para sa refactoring at mga pagsubok. Siyempre, ipinapalagay nito na walang anumang pagmamadali (ngunit kailan mangyayari iyon).dito .
11. Mga magic na numero
Ang mga magic number ay isang anti-pattern kung saan ang lahat ng uri ng mga constant ay ginagamit sa isang programa nang walang anumang paliwanag sa kanilang layunin o kahulugan. Ibig sabihin, sa pangkalahatan ay hindi maganda ang pangalan nila o sa matinding kaso, walang komentong nagpapaliwanag kung ano ang mga komento o bakit. Tulad ng spaghetti code, isa ito sa mga pinakakaraniwang anti-pattern. Ang isang taong hindi sumulat ng code ay maaaring magkaroon o walang ideya tungkol sa mga magic number o kung paano gumagana ang mga ito (at sa kalaunan, ang may-akda mismo ay hindi maipaliwanag ang mga ito). Bilang resulta, ang pagpapalit o pag-alis ng isang numero ay nagiging sanhi ng mahiwagang paghinto ng code sa paggana nang magkakasama. Halimbawa, 36 at 73. Upang labanan ang anti-pattern na ito, inirerekomenda ko ang pagsusuri ng code. Ang iyong code ay kailangang tingnan ng mga developer na hindi kasangkot sa mga nauugnay na seksyon ng code. Magiging sariwa ang kanilang mga mata at magkakaroon sila ng mga katanungan: ano ito at bakit mo ginawa iyon? At siyempre, kailangan mong gumamit ng mga paliwanag na pangalan o mag-iwan ng mga komento.12. Copy-and-paste programming
Ang copy-and-paste na programming ay isang anti-pattern kung saan ang code ng ibang tao ay hindi pinag-iisipan na kinopya at i-paste, na posibleng magresulta sa hindi inaasahang epekto. Halimbawa, ang pagkopya at pag-paste ng mga pamamaraan na may mga mathematical na kalkulasyon o kumplikadong algorithm na hindi namin lubos na nauunawaan. Maaari itong gumana para sa aming partikular na kaso, ngunit sa ilang iba pang mga pangyayari maaari itong humantong sa problema. Ipagpalagay na kailangan ko ng isang paraan upang matukoy ang maximum na numero sa isang array. Naghahalungkat sa Internet, nakita ko ang solusyong ito:
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;
}
Makakakuha tayo ng array na may mga numerong 3, 6, 1, 4, at 2, at ang pamamaraan ay nagbabalik ng 6. Mahusay, panatilihin natin ito! Ngunit sa paglaon ay nakakakuha kami ng array na binubuo ng 2.5, -7, 2, at 3, at pagkatapos ay ang aming resulta ay -7. At hindi maganda ang resultang ito. Ang problema dito ay ang Math.abs() ay nagbabalik ng absolute value. Ang kamangmangan dito ay humahantong sa sakuna, ngunit sa ilang mga sitwasyon lamang. Kung walang malalim na pag-unawa sa solusyon, maraming kaso na hindi mo mabe-verify. Ang kinopyang code ay maaari ding lumampas sa panloob na istraktura ng application, parehong istilo at sa isang mas pangunahing, antas ng arkitektura. Ang ganitong code ay magiging mas mahirap basahin at panatilihin. At siyempre, hindi natin dapat kalimutan na ang direktang pagkopya ng code ng ibang tao ay isang espesyal na uri ng plagiarism.
13. Muling pag-imbento ng gulong
Ang muling pag-imbento ng gulong ay isang anti-pattern, na kung minsan ay kilala rin bilang muling pag-imbento ng square wheel. Sa esensya, ang template na ito ay kabaligtaran ng copy-and-paste na anti-pattern na isinasaalang-alang sa itaas. Sa anti-pattern na ito, ipinapatupad ng developer ang kanyang sariling solusyon para sa isang problema kung saan mayroon nang mga solusyon. Minsan ang mga umiiral na solusyon na ito ay mas mahusay kaysa sa iniimbento ng programmer. Kadalasan, ito ay humahantong lamang sa nawawalang oras at mas mababang produktibidad: ang programmer ay maaaring hindi makahanap ng solusyon sa lahat o maaaring makahanap ng solusyon na malayo sa pinakamahusay. Iyon ay sinabi, hindi namin maaaring ibukod ang posibilidad ng paglikha ng isang independiyenteng solusyon, dahil ang paggawa nito ay isang direktang daan patungo sa pagkopya at pag-paste ng programming. Ang programmer ay dapat magabayan ng mga partikular na gawain sa programming na lumitaw upang malutas ang mga ito nang may kakayahan, maging sa pamamagitan ng paggamit ng mga handa na solusyon o sa pamamagitan ng paglikha ng mga custom na solusyon. Madalas, ang dahilan ng paggamit ng anti-pattern na ito ay pagmamadali lamang. Ang resulta ay isang mababaw na pagsusuri ng (paghahanap para sa) mga handa na solusyon. Ang muling pag-imbento ng square wheel ay isang kaso kung saan ang anti-pattern na isinasaalang-alang ay may negatibong resulta. Iyon ay, ang proyekto ay nangangailangan ng isang pasadyang solusyon, at ang developer ay lumikha nito, ngunit masama. Kasabay nito, mayroon nang magandang opsyon at matagumpay na ginagamit ito ng iba. Bottom line: isang malaking halaga ng oras ang nawala. Una, gumawa kami ng isang bagay na hindi gumagana. Pagkatapos ay sinubukan naming i-refactor ito, at sa wakas ay pinapalitan namin ito ng isang bagay na mayroon na. Ang isang halimbawa ay ang pagpapatupad ng iyong sariling custom na cache kapag marami nang pagpapatupad. Gaano ka man katalento bilang isang programmer, dapat mong tandaan na ang muling pag-imbento ng isang parisukat na gulong ay hindi bababa sa isang pag-aaksaya ng oras. At, tulad ng alam mo, ang oras ay ang pinakamahalagang mapagkukunan.14. Yo-yo problema
Ang problema sa yo-yo ay isang anti-pattern kung saan ang istraktura ng application ay labis na kumplikado dahil sa labis na pagkapira-piraso (halimbawa, isang labis na hinati-hati na chain ng mana). Ang "problema sa yo-yo" ay lumalabas kapag kailangan mong maunawaan ang isang programa na ang hierarchy ng mana ay mahaba at kumplikado, na lumilikha ng malalim na nested method call. Bilang resulta, kailangan ng mga programmer na mag-navigate sa pagitan ng maraming iba't ibang klase at pamamaraan upang masuri ang pag-uugali ng programa. Ang pangalan ng anti-pattern na ito ay nagmula sa pangalan ng laruan. Bilang halimbawa, tingnan natin ang sumusunod na inheritance chain: Mayroon kaming Technology interface:
public interface Technology {
void turnOn();
}
Ang interface ng Transport ay nagmamana nito:
public interface Transport extends Technology {
boolean fillUp();
}
At pagkatapos ay mayroon kaming isa pang interface, GroundTransport:
public interface GroundTransportation extends Transport {
void startMove();
void brake();
}
At mula doon, nakukuha namin ang abstract na klase ng Kotse:
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();
}
Susunod ay ang abstract na klase ng Volkswagen:
public abstract class Volkswagen extends Car {
@Override
public void startMove() {
/* some implementation */
}
@Override
public void brake() {
/* some implementation */
}
}
At sa wakas, isang partikular na modelo:
public class VolkswagenAmarok extends Volkswagen {
@Override
public void fixCar(){
/* some implementation */
}
}
Pinipilit kami ng chain na ito na maghanap ng mga sagot sa mga tanong tulad ng:
-
Ilang mga pamamaraan ang
VolkswagenAmarok
mayroon? -
Anong uri ang dapat ipasok sa halip na tandang pananong upang makamit ang maximum na abstraction:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. Hindi sinasadyang pagiging kumplikado
Ang hindi kinakailangang kumplikado ay isang anti-pattern kung saan ang mga hindi kinakailangang komplikasyon ay ipinakilala sa isang solusyon.
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();
}
}
At ayon dito, mayroon kaming enum na ito:
public enum ServiceType {
CAR(),
USER(),
FILE(),
PLAN(),
CUSTOMER()
}
Ang lahat ay tila simple at mabuti... Ngunit paano ang iba pang mga pamamaraan? Sa katunayan, lahat sila ay magkakaroon din ng isang bungkos ng switch
mga pahayag at isang bungkos ng halos magkaparehong mga query sa database, na kung saan naman ay lubos na magpapalubha at magpapalaki sa ating klase. Paano magiging mas madali ang lahat ng ito? I-upgrade natin nang kaunti ang ating 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;
}
Ngayon ang bawat uri ay may mga pangalan ng orihinal na mga field ng talahanayan nito. Bilang resulta, ang paraan para sa paglikha ng isang paglalarawan ay nagiging:
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);
}
Maginhawa, simple, at compact, hindi ba? Ang indikasyon ng isang mahusay na developer ay hindi kahit gaano kadalas siya gumamit ng mga pattern, ngunit kung gaano kadalas niya iniiwasan ang mga anti-pattern. Ang kamangmangan ay ang pinakamasamang kaaway, dahil kailangan mong malaman ang iyong mga kaaway sa pamamagitan ng paningin. Well, iyon lang ang mayroon ako para sa araw na ito. Salamat, lahat! :)
GO TO FULL VERSION