8. Złoty młot
Złoty młotek to antywzorzec określony przez pewność, że dane rozwiązanie ma uniwersalne zastosowanie. Przykłady:-
Po napotkaniu problemu i znalezieniu wzorca idealnego rozwiązania, programista stara się wkleić ten wzorzec wszędzie, stosując go w bieżących i wszystkich przyszłych projektach, zamiast szukać odpowiednich rozwiązań dla konkretnych przypadków.
-
Niektórzy programiści stworzyli kiedyś własny wariant pamięci podręcznej dla określonej sytuacji (ponieważ nic innego nie było odpowiednie). Później, w kolejnym projekcie, który nie obejmował żadnej specjalnej logiki pamięci podręcznej, ponownie użyli swojego wariantu zamiast korzystania z gotowych bibliotek (na przykład Ehcache). Rezultatem była masa błędów i niezgodności, a także mnóstwo zmarnowanego czasu i smażonych nerwów.
Każdy może zakochać się w tym antywzorcu. Jeśli jesteś początkującym, możesz nie mieć wiedzy na temat wzorców projektowych. Może to skłonić cię do próby rozwiązania wszystkich problemów w jeden sposób, który opanowałeś. Jeśli mówimy o profesjonalistach, nazywamy to profesjonalną deformacją lub nerdview. Masz swoje preferowane wzorce projektowe i zamiast używać właściwego, używasz swojego ulubionego, wychodząc z założenia, że dobre dopasowanie w przeszłości gwarantuje taki sam rezultat w przyszłości.
Ta pułapka może przynieść bardzo smutne skutki — od złej, niestabilnej i trudnej w utrzymaniu implementacji do całkowitej porażki projektu. Tak jak nie ma jednej pigułki na wszystkie choroby, tak nie ma jednego wzoru na każdą okazję.
9. Przedwczesna optymalizacja
Przedwczesna optymalizacja to antywzorzec, którego nazwa mówi sama za siebie.10. Kod spaghetti
Kod spaghetti to antywzorzec zdefiniowany przez kod o słabej strukturze, zagmatwany i trudny do zrozumienia, zawierający wszelkiego rodzaju rozgałęzienia, takie jak zawijanie wyjątków, warunków i pętli. Poprzednio operator goto był głównym sprzymierzeńcem tego antywzorca. Instrukcje Goto nie są już tak naprawdę używane, co szczęśliwie eliminuje szereg związanych z tym trudności i problemów.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;
}
}
}
}
}
Wygląda okropnie, prawda? Niestety, jest to najczęstszy antywzorzec :( Nawet osoba, która napisze taki kod, nie będzie w stanie go w przyszłości zrozumieć. Inni programiści, którzy zobaczą kod, pomyślą: „Cóż, jeśli to działa, to dobrze — lepiej tego nie dotykać”. Często metoda jest początkowo prosta i bardzo przejrzysta, ale w miarę dodawania nowych wymagań metoda jest stopniowo obarczana coraz większą liczbą instrukcji warunkowych, zamieniając ją w takie monstrum. Jeśli taka metoda pojawi się komunikat, musisz zrefaktoryzować go całkowicie lub przynajmniej najbardziej zagmatwane części. Zazwyczaj podczas planowania projektu przeznacza się czas na refaktoryzację, na przykład 30% czasu sprintu jest przeznaczone na refaktoryzację i testy. Oczywiście przy założeniu, że że nie ma pośpiechu (ale kiedy to się w ogóle zdarza).tutaj .
11. Magiczne liczby
Liczby magiczne to antywzorzec, w którym w programie używane są wszelkiego rodzaju stałe bez żadnego wyjaśnienia ich celu lub znaczenia. Oznacza to, że generalnie są źle nazwane lub w skrajnych przypadkach nie ma komentarza wyjaśniającego, czym są komentarze i dlaczego. Podobnie jak kod spaghetti, jest to jeden z najpopularniejszych antywzorców. Ktoś, kto nie napisał kodu, może mieć pojęcie o magicznych liczbach lub ich działaniu (a z czasem sam autor nie będzie w stanie ich wyjaśnić). W rezultacie zmiana lub usunięcie numeru powoduje, że kod magicznie przestaje działać razem. Na przykład 36 i 73. Aby zwalczyć ten antywzorzec, polecam przegląd kodu. Twój kod musi zostać przejrzany przez programistów, którzy nie są zaangażowani w odpowiednie sekcje kodu. Ich oczy będą świeże i będą mieć pytania: co to jest i dlaczego to zrobiłeś? I oczywiście musisz używać nazw wyjaśniających lub zostawiać komentarze.12. Programowanie kopiuj-wklej
Programowanie typu „kopiuj i wklej” to antywzorzec, w którym cudzy kod jest bezmyślnie kopiowany i wklejany, co może skutkować nieoczekiwanymi efektami ubocznymi. Na przykład kopiowanie i wklejanie metod z obliczeniami matematycznymi lub złożonymi algorytmami, których nie do końca rozumiemy. Może to zadziałać w naszym konkretnym przypadku, ale w niektórych innych okolicznościach może prowadzić do kłopotów. Załóżmy, że potrzebuję metody określania maksymalnej liczby w tablicy. Szperając w internecie znalazłem takie rozwiązanie: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;
}
Otrzymujemy tablicę z liczbami 3, 6, 1, 4 i 2, a metoda zwraca 6. Świetnie, zostawmy to! Ale później otrzymujemy tablicę składającą się z 2,5, -7, 2 i 3, a następnie naszym wynikiem jest -7. I ten wynik nie jest dobry. Problem polega na tym, że Math.abs() zwraca wartość bezwzględną. Nieznajomość tego prowadzi do katastrofy, ale tylko w określonych sytuacjach. Bez dogłębnego zrozumienia rozwiązania jest wiele przypadków, których nie będziesz w stanie zweryfikować. Skopiowany kod może również wykraczać poza wewnętrzną strukturę aplikacji, zarówno stylistycznie, jak i na bardziej fundamentalnym, architektonicznym poziomie. Taki kod będzie trudniejszy do odczytania i utrzymania. I oczywiście nie wolno nam zapominać, że bezpośrednie skopiowanie czyjegoś kodu jest szczególnym rodzajem plagiatu.
13. Wymyślanie koła na nowo
Ponowne wynalezienie koła to antywzorzec, czasami znany również jako ponowne wynalezienie kwadratowego koła. Zasadniczo ten szablon jest przeciwieństwem antywzorca kopiuj i wklej omówionego powyżej. W tym antywzorcu programista implementuje własne rozwiązanie problemu, dla którego rozwiązania już istnieją. Czasami te istniejące rozwiązania są lepsze niż to, co wymyśli programista. Najczęściej prowadzi to tylko do straconego czasu i niższej produktywności: programista może w ogóle nie znaleźć rozwiązania lub może znaleźć rozwiązanie dalekie od najlepszego. To powiedziawszy, nie możemy wykluczyć możliwości stworzenia niezależnego rozwiązania, ponieważ jest to bezpośrednia droga do programowania metodą „kopiuj i wklej”. Programista powinien kierować się konkretnymi zadaniami programistycznymi, które się pojawiają, aby umiejętnie je rozwiązać, czy to korzystając z gotowych rozwiązań, czy też tworząc rozwiązania niestandardowe. Bardzo często, powodem użycia tego antywzorca jest po prostu pośpiech. Rezultatem jest płytka analiza (poszukiwanie) gotowych rozwiązań. Ponowne wynalezienie kwadratowego koła to przypadek, w którym rozważany antywzorzec ma negatywny wynik. Oznacza to, że projekt wymaga niestandardowego rozwiązania, a programista je tworzy, ale źle. Jednocześnie dobra opcja już istnieje i inni z powodzeniem z niej korzystają. Konkluzja: traci się ogromną ilość czasu. Najpierw tworzymy coś, co nie działa. Potem próbujemy to refaktoryzować, a na koniec zastępujemy czymś, co już istniało. Przykładem jest implementacja własnej niestandardowej pamięci podręcznej, gdy istnieje już wiele implementacji. Bez względu na to, jak utalentowany jesteś jako programista, powinieneś pamiętać, że odkrywanie kwadratowego koła na nowo jest co najmniej stratą czasu. A jak wiadomo, czas jest najcenniejszym zasobem.14. Problem jo-jo
Problem jo-jo to antywzorzec, w którym struktura aplikacji jest nadmiernie skomplikowana ze względu na nadmierną fragmentację (na przykład nadmiernie podzielony łańcuch dziedziczenia). „Problem jo-jo” pojawia się, gdy trzeba zrozumieć program, którego hierarchia dziedziczenia jest długa i złożona, tworząc głęboko zagnieżdżone wywołania metod. W rezultacie programiści muszą nawigować między wieloma różnymi klasami i metodami, aby sprawdzić zachowanie programu. Nazwa tego antywzorca pochodzi od nazwy zabawki. Jako przykład spójrzmy na następujący łańcuch dziedziczenia: Mamy interfejs technologii:public interface Technology {
void turnOn();
}
Interfejs Transport dziedziczy go:
public interface Transport extends Technology {
boolean fillUp();
}
A potem mamy inny interfejs, GroundTransport:
public interface GroundTransportation extends Transport {
void startMove();
void brake();
}
Stamtąd wyprowadzamy abstrakcyjną klasę Car:
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();
}
Następna jest abstrakcyjna klasa Volkswagena:
public abstract class Volkswagen extends Car {
@Override
public void startMove() {
/* some implementation */
}
@Override
public void brake() {
/* some implementation */
}
}
I na koniec konkretny model:
public class VolkswagenAmarok extends Volkswagen {
@Override
public void fixCar(){
/* some implementation */
}
}
Ten łańcuch zmusza nas do poszukiwania odpowiedzi na pytania takie jak:
-
Ile ma metod
VolkswagenAmarok
? -
Jaki typ należy wstawić zamiast znaku zapytania, aby uzyskać maksymalną abstrakcję:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. Przypadkowa złożoność
Niepotrzebna złożoność to antywzorzec, w którym do rozwiązania wprowadzane są niepotrzebne komplikacje.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();
}
}
I odpowiednio, mamy to wyliczenie:
public enum ServiceType {
CAR(),
USER(),
FILE(),
PLAN(),
CUSTOMER()
}
Wszystko wydaje się proste i dobre... Ale co z innymi metodami? Rzeczywiście, wszystkie one będą miały również kilka switch
instrukcji i kilka prawie identycznych zapytań do bazy danych, co z kolei znacznie skomplikuje i rozrośnie naszą klasę. Jak można to wszystko uprościć? Zaktualizujmy nieco nasze wyliczenie:
@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;
}
Teraz każdy typ ma nazwy oryginalnych pól swojej tabeli. W rezultacie metoda tworzenia opisu staje się:
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);
}
Wygodny, prosty i kompaktowy, nie sądzisz? Wyznacznikiem dobrego programisty nie jest nawet to, jak często używa wzorców, ale raczej to, jak często unika antywzorców. Ignorancja jest najgorszym wrogiem, ponieważ wrogów trzeba znać z widzenia. Cóż, to wszystko, co mam na dziś. Dziękuje wszystkim! :)