CodeGym /Java blog /Véletlen /Mik azok az anti-minták? Nézzünk néhány példát (2. rész)
John Squirrels
Szint
San Francisco

Mik azok az anti-minták? Nézzünk néhány példát (2. rész)

Megjelent a csoportban
Mik azok az anti-minták? Nézzünk néhány példát (1. rész) Ma folytatjuk a legnépszerűbb anti-minták áttekintését. Ha lemaradtál az első részről, itt van. Mik azok az anti-minták?  Nézzünk néhány példát (2. rész) – 1Tehát a tervezési minták a legjobb gyakorlatok. Más szóval, ezek példák a konkrét problémák jó, jól bevált módszereire. Az anti-mintázatok viszont pont az ellentétei, abban az értelemben, hogy különböző problémák megoldása során előforduló buktatók vagy hibák mintái (gonosz minták). Folytassuk a következő szoftverfejlesztési anti-mintával.

8. Arany kalapács

Az aranykalapács egy antiminta, amelyet az a bizalom határoz meg, hogy egy adott megoldás univerzálisan alkalmazható. Példák:
  1. Miután találkozott egy problémával, és megtalálta a tökéletes megoldás mintáját, a programozó ezt a mintát igyekszik mindenhol ragasztani, alkalmazza a jelenlegi és minden jövőbeli projektre, ahelyett, hogy konkrét esetekre keresné a megfelelő megoldást.

  2. Egyes fejlesztők egyszer létrehozták a gyorsítótár saját változatát egy adott helyzethez (mivel semmi más nem volt megfelelő). Később, a következő projektben, amely nem tartalmazott különösebb gyorsítótár-logikát, a kész könyvtárak (például Ehcache) helyett ismét az ő változatukat használták. Az eredmény egy rakás hiba és összeférhetetlenség, valamint sok elvesztegetett idő és felpörgetett ideg volt.

    Bárki bedőlhet ennek az antimintának. Ha Ön kezdő, előfordulhat, hogy nem ismeri a tervezési mintákat. Ez arra késztetheti, hogy megpróbáljon minden problémát az általa elsajátított egyetlen módon megoldani. Ha szakemberekről beszélünk, akkor ezt nevezzük szakmai deformációnak vagy nerdview-nak. Megvannak a saját preferált tervezési mintái, és ahelyett, hogy a megfelelőt használnád, inkább a kedvencedet használod, feltételezve, hogy a múltbeli jó illeszkedés ugyanazt az eredményt garantálja a jövőben is.

    Ez a buktató nagyon szomorú eredményeket hozhat – a rossz, instabil és nehezen karbantartható megvalósítástól a projekt teljes kudarcáig. Ahogyan nincs minden betegségre egy tabletta, úgy nincs minden alkalomra egységes tervezési minta.

9. Korai optimalizálás

Az idő előtti optimalizálás egy anti-minta, amelynek neve önmagáért beszél.
"A programozók rengeteg időt töltenek azzal, hogy gondolkodjanak és aggódjanak a kód nem kritikus helyei miatt, és megpróbálják optimalizálni azokat, ami csak negatívan befolyásolja a későbbi hibakeresést és támogatást. Általában el kell felejtenünk az optimalizálást, mondjuk az esetek 97%-ában. , az idő előtti optimalizálás minden rossz gyökere. Ennek ellenére minden figyelmet a maradék 3%-ra kell fordítanunk." – Donald Knuth
Például indexek idő előtti hozzáadása egy adatbázishoz. Miért rossz ez? Nos, abban rossz, hogy az indexeket bináris faként tárolják. Ennek eredményeként minden új érték hozzáadásakor és törlésekor a fa újraszámításra kerül, ami erőforrásokat és időt emészt fel. Ezért az indexeket csak sürgős szükség esetén szabad hozzáadni (ha nagy mennyiségű adat van és a lekérdezések túl sokáig tartanak), és csak a legfontosabb mezőkhöz (a leggyakrabban lekérdezett mezőkhöz).

10. Spagetti kód

A spagetti kód egy olyan anti-minta, amelyet rosszul strukturált, zavaros és nehezen érthető kód határoz meg, és mindenféle elágazást tartalmaz, például tördelési kivételeket, feltételeket és ciklusokat. Korábban a goto operátor volt az anti-minta fő szövetségese. A Goto utasításokat már nem igazán használják, ami szerencsére kiküszöböl számos kapcsolódó nehézséget és problémát.

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;
               }
           }
       }
   }
}
Szörnyen néz ki, nem? Sajnos ez a legelterjedtebb anti-minta :( Még az sem fogja tudni megérteni a jövőben, aki ilyen kódot ír. Más fejlesztők, akik látják a kódot, azt gondolják majd: "Nos, ha működik, akkor oké… jobb, ha nem nyúlunk hozzá". Gyakran egy metódus kezdetben egyszerű és nagyon átlátszó, de ahogy új követelmények jelentkeznek, a metódus fokozatosan egyre több feltételes kijelentéssel nyeregbe kerül, ami ilyen szörnyűséggé változik. Ha egy ilyen módszer jelenik meg, akkor vagy teljesen, vagy legalábbis a legzavaróbb részeket újra kell formázni. Jellemzően egy projekt ütemezésekor van idő a refaktorálásra, pl. hogy nincs semmi rohanás (de ez mikor történik meg).itt .

11. Varázsszámok

A mágikus számok egy antiminta, amelyben mindenféle állandót használnak egy programban anélkül, hogy a céljukat vagy jelentésüket megmagyaráznák. Vagyis általában rosszul vannak megnevezve, vagy szélsőséges esetben nincs megjegyzés, amely elmagyarázza, hogy mik a megjegyzések és miért. A spagetti kódhoz hasonlóan ez is az egyik leggyakoribb anti-minta. Valaki, aki nem írta meg a kódot, lehet, hogy van fogalma a bűvös számokról vagy azok működéséről (és idővel maga a szerző sem fogja tudni megmagyarázni őket). Ennek eredményeként egy szám megváltoztatása vagy eltávolítása azt eredményezi, hogy a kód varázslatos módon leáll. Például 36 és 73. Az anti-mintázat elleni küzdelem érdekében javaslom a kód áttekintését. A kódot olyan fejlesztőknek kell megnézniük, akik nem vesznek részt a kód megfelelő szakaszaiban. Friss lesz a tekintetük, és kérdéseik lesznek: mi ez és miért tetted ezt? És természetesen magyarázó neveket kell használnia, vagy megjegyzéseket kell hagynia.

12. Másolás és beillesztés programozás

A másolás és beillesztés programozás egy olyan anti-minta, amelyben valaki más kódját meggondolatlanul másolják és illesztik be, ami váratlan mellékhatásokat eredményezhet. Például másolási és beillesztési módszerek matematikai számításokkal vagy bonyolult algoritmusokkal, amelyeket nem teljesen értünk. Lehet, hogy a mi esetünkben működik, de más körülmények között bajhoz vezethet. Tegyük fel, hogy szükségem van egy módszerre egy tömb maximális számának meghatározásához. Az internetet keresgélve ezt a megoldást találtam:

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;
}
Kapunk egy tömböt a 3, 6, 1, 4 és 2 számokkal, és a metódus 6-ot ad vissza. Remek, maradjunk! De később kapunk egy 2,5, -7, 2 és 3-ból álló tömböt, és akkor az eredményünk -7. És ez az eredmény nem jó. A probléma itt az, hogy a Math.abs() az abszolút értéket adja vissza. Ennek nem ismerete katasztrófához vezet, de csak bizonyos helyzetekben. A megoldás alapos ismerete nélkül sok olyan eset van, amelyet nem fog tudni ellenőrizni. A másolt kód túlmutathat az alkalmazás belső struktúráján, mind stilisztikailag, mind alapvetőbb, építészeti szinten. Az ilyen kódokat nehezebb lesz elolvasni és karbantartani. És persze nem szabad megfeledkeznünk arról, hogy valaki más kódjának közvetlen másolása a plágium egy különleges fajtája.

13. A kerék újrafeltalálása

A kerék újrafeltalálása anti-minta, más néven a négyzet alakú kerék újrafeltalálása. Ez a sablon lényegében az ellentéte a fent említett másolás-beillesztés elleni mintának. Ebben az antimintában a fejlesztő saját megoldást valósít meg egy olyan problémára, amelyre már létezik megoldás. Néha ezek a meglévő megoldások jobbak, mint amit a programozó kitalál. Ez legtöbbször csak időveszteséggel és alacsonyabb termelékenységgel jár: előfordulhat, hogy a programozó egyáltalán nem talál megoldást, vagy olyan megoldást talál, amely messze nem a legjobb. Ennek ellenére nem zárhatjuk ki egy független megoldás létrehozásának lehetőségét, mert ez egy közvetlen út a másolás-beillesztés programozáshoz. A programozót a felmerülő konkrét programozási feladatok vezéreljék azok szakszerű megoldása érdekében, akár kész megoldások felhasználásával, akár egyedi megoldások készítésével. Nagyon gyakran, ennek az antimintának az oka egyszerűen a sietség. Az eredmény a kész megoldások (kereső) sekély elemzése. A négyzet alakú kerék újrafeltalálása olyan eset, amikor a vizsgált anti-minta negatív eredménnyel jár. Vagyis a projekthez egyedi megoldás kell, és a fejlesztő megalkotja, de rosszul. Ugyanakkor egy jó lehetőség már létezik, és mások sikeresen használják. A lényeg: rengeteg idő vész el. Először is létrehozunk valamit, ami nem működik. Utána megpróbáljuk újratermelni, végül valami már létezővel helyettesítjük. Példa erre a saját egyéni gyorsítótár megvalósítása, amikor már rengeteg megvalósítás létezik. Nem számít, mennyire tehetséges programozóként, ne feledje, hogy egy négyzet alakú kerék újrafeltalálása legalább időpocsékolás. És mint tudod, az idő a legértékesebb erőforrás.

14. Jojó probléma

A yo-yo probléma egy anti-minta, amelyben az alkalmazás szerkezete túlságosan bonyolult a túlzott töredezettség miatt (például túlzottan felosztott öröklési lánc). A "jojó-probléma" akkor merül fel, amikor meg kell értenie egy olyan programot, amelynek öröklődési hierarchiája hosszú és összetett, és mélyen beágyazott metódushívásokat hoz létre. Ennek eredményeként a programozóknak sok különböző osztály és módszer között kell navigálniuk, hogy ellenőrizzék a program viselkedését. Ennek az anti-mintának a neve a játék nevéből származik. Példaként nézzük a következő öröklési láncot: Technológiai interfészünk van:

public interface Technology {
   void turnOn();
}
A szállítási felület örökli:

public interface Transport extends Technology {
   boolean fillUp();
}
És akkor van egy másik felületünk is, a GroundTransport:

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
Ebből pedig egy absztrakt autóosztályt vezetünk le:

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();
}
A következő az elvont Volkswagen osztály:

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
És végül egy konkrét modell:

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
Ez a lánc arra késztet bennünket, hogy olyan kérdésekre keressük a választ, mint:
  1. Hány módszere VolkswagenAmarokvan?

  2. Milyen típust kell beszúrni a kérdőjel helyett a maximális absztrakció elérése érdekében:

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
Nehéz gyorsan válaszolni az ilyen kérdésekre – ehhez meg kell néznünk és ki kell vizsgálnunk, és könnyen összezavarodhatunk. És mi van akkor, ha a hierarchia sokkal nagyobb, hosszabb és bonyolultabb, mindenféle túlterheléssel és felülírással? A szerkezet, amivel rendelkeznénk, a túlzott töredezettség miatt homályos lenne. A legjobb megoldás a szükségtelen megosztottság csökkentése lenne. Esetünkben a Technológia → Autó → VolkswagenAmarok lehetőséget hagynánk.

15. Véletlen bonyolultság

A szükségtelen bonyolultság egy anti-minta, amelyben szükségtelen bonyodalmakat vezetnek be a megoldásba.
"Bármely bolond tud olyan kódot írni, amit a számítógép megért. A jó programozók olyan kódot írnak, amit az emberek is megértenek." – Martin Fowler
Tehát mi az összetettség? Meghatározható az egyes műveletek nehézségi fokaként a programban. A komplexitás általában két típusra osztható. A bonyolultság első fajtája a rendszer funkcióinak száma. Ez csak egy módon csökkenthető – néhány funkció eltávolításával. A meglévő módszereket figyelemmel kell kísérni. A módszert el kell távolítani, ha már nem használják, vagy még mindig használják, de nem hoznak értéket. Sőt, fel kell mérni, hogy az alkalmazásban szereplő összes metódust hogyan használjuk, hogy megértsük, hol érdemes befektetést (sok kód-újrafelhasználás), és mire lehet nemet mondani. A bonyolultság második típusa a szükségtelen bonyolultság. Csak professzionális megközelítéssel gyógyítható. Ahelyett, hogy valami "menőt" csinálna (nem csak a fiatal fejlesztők fogékonyak erre a betegségre), át kell gondolni, hogyan lehet ezt a lehető legegyszerűbben megtenni, mert a legjobb megoldás mindig egyszerű. Tegyük fel például, hogy vannak kis kapcsolódó tábláink néhány entitás leírásával, például egy felhasználóval: Mik azok az anti-minták?  Nézzünk néhány példát (2. rész) – 3Tehát megvan a felhasználó azonosítója, annak a nyelvnek az azonosítója, amelyen a leírás készült, és maga a leírás. Hasonlóképpen, vannak segédleíróink az autókhoz, aktákhoz, tervekhez és vásárlói táblákhoz. Akkor hogyan nézne ki új értékeket beszúrni az ilyen táblákba?

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();
   }
}
És ennek megfelelően van ez a felsorolásunk:

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
Minden egyszerűnek és jónak tűnik... De mi a helyzet a többi módszerrel? Valójában mindegyikben lesz egy csomó switchutasítás és egy csomó majdnem azonos adatbázis-lekérdezés, ami viszont nagymértékben megbonyolítja és felduzzasztja osztályunkat. Hogyan lehetne mindezt könnyebbé tenni? Frissítsük egy kicsit az enumunkat:

@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;
}
Most minden típus rendelkezik a tábla eredeti mezőivel. Ennek eredményeként a leírás létrehozásának módja a következő:

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);
   }
Kényelmes, egyszerű és kompakt, nem gondolod? A jó fejlesztőt nem is az mutatja, hogy milyen gyakran használ mintákat, hanem az, hogy milyen gyakran kerüli az anti-mintákat. A tudatlanság a legrosszabb ellenség, mert látásból kell ismerned ellenségeidet. Nos, mára csak ennyi van. Köszönöm mindenkinek! :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION