
8. Martello d'oro
Un martello d'oro è un anti-modello definito dalla fiducia che una particolare soluzione sia universalmente applicabile. Esempi:-
Dopo aver incontrato un problema e aver trovato uno schema per la soluzione perfetta, un programmatore cerca di applicare questo schema ovunque, applicandolo ai progetti attuali e futuri, invece di cercare le soluzioni appropriate per casi specifici.
-
Alcuni sviluppatori una volta hanno creato la propria variante di una cache per una situazione specifica (perché nient'altro era adatto). Successivamente, nel progetto successivo che non prevedeva una logica cache speciale, hanno utilizzato di nuovo la loro variante invece di utilizzare librerie già pronte (ad esempio, Ehcache). Il risultato è stato un sacco di bug e incompatibilità, oltre a un sacco di tempo perso e nervi fritti.
Chiunque può innamorarsi di questo anti-modello. Se sei un principiante, potresti non essere informato sui modelli di progettazione. Questo potrebbe portarti a provare a risolvere tutti i problemi nell'unico modo che hai imparato. Se parliamo di professionisti, chiamiamo questa deformazione professionale o nerdview. Hai i tuoi modelli di design preferiti e invece di usare quello giusto, usi il tuo preferito, supponendo che un buon adattamento in passato garantisca lo stesso risultato in futuro.
Questa trappola può produrre risultati molto tristi: da un'implementazione cattiva, instabile e difficile da mantenere a un completo fallimento del progetto. Proprio come non esiste una pillola per tutte le malattie, non esiste un modello di progettazione per tutte le occasioni.
9. Ottimizzazione prematura
L'ottimizzazione prematura è un anti-pattern il cui nome parla da sé.10. Codice spaghetti
Il codice spaghetti è un anti-pattern definito da un codice mal strutturato, confuso e difficile da comprendere, contenente tutti i tipi di ramificazioni, come eccezioni di wrapping, condizioni e cicli. In precedenza, l'operatore goto era il principale alleato di questo anti-pattern. Le dichiarazioni Goto non sono più realmente utilizzate, il che elimina felicemente una serie di difficoltà e problemi associati.
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;
}
}
}
}
}
Sembra orribile, non è vero? Sfortunatamente, questo è l'anti-pattern più comune :( Anche la persona che scrive tale codice non sarà in grado di capirlo in futuro. Altri sviluppatori che vedranno il codice penseranno: "Bene, se funziona, allora va bene — è meglio non toccarlo". Spesso, un metodo è inizialmente semplice e molto trasparente, ma man mano che vengono aggiunti nuovi requisiti, il metodo viene gradualmente gravato da un numero sempre maggiore di affermazioni condizionali, trasformandolo in una mostruosità come questa. Se un tale metodo appare, è necessario rifattorizzare completamente o almeno le parti più confuse.In genere, durante la pianificazione di un progetto, il tempo viene assegnato per il refactoring, ad esempio, il 30% del tempo di sprint è per il refactoring e i test.Naturalmente, questo presuppone che non c'è fretta (ma quando mai succede).qui .
11. Numeri magici
I numeri magici sono un anti-pattern in cui tutti i tipi di costanti vengono utilizzati in un programma senza alcuna spiegazione del loro scopo o significato. Cioè, sono generalmente nominati male o, in casi estremi, non ci sono commenti che spiegano cosa sono i commenti o perché. Come il codice degli spaghetti, questo è uno degli anti-pattern più comuni. Qualcuno che non ha scritto il codice potrebbe avere o meno la minima idea dei numeri magici o di come funzionano (e col tempo l'autore stesso non sarà in grado di spiegarli). Di conseguenza, la modifica o la rimozione di un numero fa sì che il codice smetta magicamente di funzionare tutti insieme. Ad esempio, 36 e 73. Per combattere questo anti-pattern, consiglio una revisione del codice. Il tuo codice deve essere esaminato da sviluppatori che non sono coinvolti nelle sezioni pertinenti del codice. I loro occhi saranno freschi e avranno domande: cos'è questo e perché l'hai fatto? E, naturalmente, devi usare nomi esplicativi o lasciare commenti.12. Programmazione copia e incolla
La programmazione copia e incolla è un anti-pattern in cui il codice di qualcun altro viene copiato e incollato sconsideratamente, con possibili effetti collaterali imprevisti. Ad esempio, copiare e incollare metodi con calcoli matematici o algoritmi complessi che non comprendiamo appieno. Potrebbe funzionare per il nostro caso particolare, ma in alcune altre circostanze potrebbe causare problemi. Supponiamo che io abbia bisogno di un metodo per determinare il numero massimo in un array. Rovistando in Internet, ho trovato questa soluzione:
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;
}
Otteniamo un array con i numeri 3, 6, 1, 4 e 2 e il metodo restituisce 6. Fantastico, teniamolo! Ma in seguito otteniamo un array composto da 2,5, -7, 2 e 3, e quindi il nostro risultato è -7. E questo risultato non va bene. Il problema qui è che Math.abs() restituisce il valore assoluto. L'ignoranza di ciò porta al disastro, ma solo in determinate situazioni. Senza una comprensione approfondita della soluzione, ci sono molti casi che non sarai in grado di verificare. Il codice copiato può anche andare oltre la struttura interna dell'applicazione, sia dal punto di vista stilistico che a un livello architettonico più fondamentale. Tale codice sarà più difficile da leggere e mantenere. E, naturalmente, non dobbiamo dimenticare che copiare direttamente il codice di qualcun altro è un tipo speciale di plagio.
13. Reinventare la ruota
Reinventare la ruota è un anti-modello, talvolta noto anche come reinventare la ruota quadrata. In sostanza, questo modello è l'opposto dell'anti-pattern copia e incolla considerato sopra. In questo anti-pattern, lo sviluppatore implementa la propria soluzione per un problema per il quale esistono già soluzioni. A volte queste soluzioni esistenti sono migliori di ciò che il programmatore inventa. Molto spesso, questo porta solo alla perdita di tempo e alla minore produttività: il programmatore potrebbe non trovare affatto una soluzione o potrebbe trovare una soluzione tutt'altro che migliore. Detto questo, non possiamo escludere la possibilità di creare una soluzione indipendente, perché farlo è una strada diretta per la programmazione copia e incolla. Il programmatore dovrebbe essere guidato dalle attività di programmazione specifiche che si presentano per risolverle in modo competente, utilizzando soluzioni già pronte o creando soluzioni personalizzate. Molto spesso, la ragione per usare questo anti-pattern è semplicemente la fretta. Il risultato è un'analisi superficiale di (ricerca di) soluzioni già pronte. Reinventare la ruota quadra è un caso in cui l'anti-pattern in esame ha un esito negativo. Cioè, il progetto richiede una soluzione personalizzata e lo sviluppatore lo crea, ma male. Allo stesso tempo, esiste già una buona opzione e altri la stanno utilizzando con successo. In conclusione: si perde un'enorme quantità di tempo. Per prima cosa, creiamo qualcosa che non funziona. Quindi proviamo a rifattorizzarlo e infine lo sostituiamo con qualcosa che già esisteva. Un esempio è l'implementazione della propria cache personalizzata quando esistono già molte implementazioni. Non importa quanto tu sia talentuoso come programmatore, dovresti ricordare che reinventare una ruota quadrata è come minimo una perdita di tempo. E, come sai, il tempo è la risorsa più preziosa.14. Problema con lo yo-yo
Il problema yo-yo è un anti-pattern in cui la struttura dell'applicazione è eccessivamente complicata a causa di un'eccessiva frammentazione (ad esempio, una catena di ereditarietà eccessivamente suddivisa). Il "problema yo-yo" sorge quando è necessario comprendere un programma la cui gerarchia di ereditarietà è lunga e complessa, creando chiamate di metodo profondamente nidificate. Di conseguenza, i programmatori devono navigare tra molte classi e metodi diversi per ispezionare il comportamento del programma. Il nome di questo anti-pattern deriva dal nome del giocattolo. Ad esempio, diamo un'occhiata alla seguente catena di ereditarietà: Abbiamo un'interfaccia Technology:
public interface Technology {
void turnOn();
}
L'interfaccia di trasporto lo eredita:
public interface Transport extends Technology {
boolean fillUp();
}
E poi abbiamo un'altra interfaccia, GroundTransport:
public interface GroundTransportation extends Transport {
void startMove();
void brake();
}
E da lì, deriviamo una classe Car astratta:
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();
}
La prossima è la classe Volkswagen astratta:
public abstract class Volkswagen extends Car {
@Override
public void startMove() {
/* some implementation */
}
@Override
public void brake() {
/* some implementation */
}
}
E infine, un modello specifico:
public class VolkswagenAmarok extends Volkswagen {
@Override
public void fixCar(){
/* some implementation */
}
}
Questa catena ci costringe a cercare risposte a domande come:
-
Quanti metodi
VolkswagenAmarok
ha? -
Quale tipo deve essere inserito al posto del punto interrogativo per ottenere la massima astrazione:
? someObj = new VolkswagenAmarok(); someObj.brake();
15. Complessità accidentale
La complessità non necessaria è un anti-modello in cui vengono introdotte complicazioni inutili per una soluzione.
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();
}
}
E di conseguenza, abbiamo questo enum:
public enum ServiceType {
CAR(),
USER(),
FILE(),
PLAN(),
CUSTOMER()
}
Sembra tutto semplice e buono... Ma per quanto riguarda gli altri metodi? In effetti, avranno anche tutti un mucchio di switch
istruzioni e un mucchio di query di database quasi identiche, che a loro volta complicheranno e gonfieranno notevolmente la nostra classe. Come si potrebbe semplificare tutto questo? Aggiorniamo un po' il nostro 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;
}
Ora ogni tipo ha i nomi dei campi originali della sua tabella. Di conseguenza, il metodo per creare una descrizione diventa:
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);
}
Comodo, semplice e compatto, non credi? L'indicazione di un buon sviluppatore non è nemmeno la frequenza con cui utilizza i pattern, ma piuttosto la frequenza con cui evita gli anti-pattern. L'ignoranza è il peggior nemico, perché devi conoscere i tuoi nemici di vista. Bene, questo è tutto quello che ho per oggi. Grazie a tutti! :)
GO TO FULL VERSION