Styleguide durante la codifica in un linguaggio statico [duplicato]

4

Attualmente sono un ingegnere junior e appassionato di apprendimento delle migliori pratiche e di espansione della mia esperienza. La mia domanda riguarda qualsiasi linguaggio di programmazione statico come Java, C #, C ++ ecc.

Quando scrivo codice, mi piace renderlo facile da leggere. Secondo me, leggere il codice dovrebbe essere come leggere un libro. Dovrebbe essere fluente ed elegante. Quindi, anche se non ho bisogno di usarli, mi piace anteporre this , super - base parole chiave ogni volta che posso. Idem per il nome della classe corrente quando voglio usare costanti o variabili / metodi statici.

Di conseguenza, un altro sviluppatore può rapidamente avere una possibilità remota. Conosce questo metodo o var è nella classe corrente o nella classe madre senza bisogno di passare alla dichiarazione. Potresti dirmi che è davvero facile farlo con i recenti IDE. Tuttavia, conosco un gruppo di ragazzi che stanno ancora lavorando con Vim, Emacs o altri editor senza queste fantastiche funzionalità.

Quando lo spieghiamo, mi piace paragonare le mie pratiche a un libro di recitazione. Tutti abbiamo letto almeno uno di questi, come Macbeth di Shakespeare. Chi non si è mai sentito frustrato di tornare all'inizio del libro per sapere chi è quel personaggio e quale parte ha nella trama? L'hai fatto così tante volte, vero?

La mia domanda può essere associata a pratiche di programmazione letterale. Tuttavia, ho pensato che le raccomandazioni di Donald Knuth riguardassero più commenti e aggiunte di macro al tuo codice.

Quindi mi piacerebbe conoscere le tue opinioni e feedback su queste pratiche. Sto facendo troppo? Dovrei tenerlo più semplice? Sto violando le regole OOP?

Ecco un esempio di codice:

class Bar {
    protected int _motherVar;

    public aBarMethod() { }
}

class Foo extends Bar {
    private static List<String> _strings;

    private int _myPrivateVar;

    public void aMethod() {
        super.aBarMethod();

        this._myPrivateVar++;
        super._motherVar -= 2;
    }

    public static String anotherMethod() {
        String outcome = "";

        for (String s : Foo._strings) {
            outcome += s;
        }

        return outcome;
    }
}
    
posta Adrien Cadet 28.02.2015 - 19:30
fonte

4 risposte

2

Sconsiglio di usare this. in questo modo, non perché è di per sé una cattiva idea. (Python, per esempio, ti costringe a farlo con self. e python ha una meritata reputazione di leggibilità.) Ma piuttosto perché la lingua non la applica. Poiché il linguaggio non lo impone, è facile dimenticarlo su una singola riga, che quindi potrebbe confondere un futuro lettore del codice. Lo stesso vale per super. . Il compilatore non ti obbliga a farlo, quindi potresti dimenticarlo e, quando lo dimentichi, la percentuale mancante disuper. diventa fuorviante per qualcuno che presume che sarà sempre lì.

L'uso di un prefisso come _ o my o m_ è migliore perché il compilatore forzerà tutte le istanze a corrispondere. Non puoi dimenticarlo, quindi qualsiasi riferimento a quell'attributo sarà evidente come membro dell'attributo.

Detto questo, il punto di @ kent-anderson nei commenti è ben preso. Idealmente, si desidera mantenere le classi e i metodi abbastanza piccoli da non rendere necessario questo genere di cose. Se, per esempio, non fai riferimento a globals, evita di utilizzare direttamente gli attributi della superclasse e mantieni i nomi dei metodi su 10-20 linee, è piuttosto facile vedere cosa sono i locali (come vengono dichiarati proprio lì) e quali sono gli attributi su di essi oggetto (tutto il resto.)

    
risposta data 03.04.2015 - 00:44
fonte
3

Penso che tutti e tre ( this. , super. e prefissi membri privati) siano superflui:

  • this. è superfluo se hai metodi relativamente piccoli, che dovresti (regola generale: fa una cosa: il codice si adatta in una singola schermata). In un piccolo metodo puoi facilmente distinguere le variabili method-local e instance / class.
  • super. è superfluo perché le classi dovrebbero essere relativamente piccole (a causa di principio di responsabilità singola ), quindi dovresti vedere facilmente se il membro a cui accedi è o non è in una classe corrente.
  • Il prefisso dei membri privati con underscore (o qualsiasi altro prefisso speciale) è superfluo perché non ti importa se qualcosa è privato o meno quando lo usi in un metodo (dovresti preoccuparti solo se è accessibile), e se ci si deve preoccupare, questo è probabilmente un odore di codice di qualche tipo, ad es stai facendo lo stato di alcune variabili pubbliche. ( il punto @ StevenBurnap è valido, ma puoi dimenticare di prefisso (in particolare dopo il refactoring) un nome utente con underscore è facile quanto puoi dimenticarti di prefissarlo con this. quando accedi, quindi penso che non sia di aiuto. )

Naturalmente, se hai 1000 o più righe di merda in una singola classe, tutte queste cose iniziano a essere importanti, ma non è una soluzione, ma piuttosto una protesi. Ho visto persone fare così tanto, e non mi ha mai aiutato a leggere un brutto codice.

    
risposta data 03.04.2015 - 01:07
fonte
2

Vorrei solo sottolineare quanto segue: Questo uso di super

super.aBarMethod();

in realtà dannoso perché disabilita l'invio dinamico per questa chiamata. Ciò significa che se una sottoclasse sovrascrive aBarMethod , chiamerai comunque quella definita in Bar , non quella sovrascritta. Probabilmente non è quello che ti aspetteresti. Quello che si supponeva dovesse essere una sfumatura stilistica si è rivelato per cambiare la semantica del codice! Potrebbe funzionare come previsto ora, ma quando inizierai a eseguire il refactoring in un secondo momento (spostando le definizioni dei metodi in giro) il tuo codice inizierà a scoppiare in modi impercettibili. Se pensi che sovrascrivere il metodo sarebbe comunque una cattiva idea, dovresti vietarlo dichiarando aBarMethod come final . 1 In ogni caso, la chiamata all'interno Foo dovrebbe leggere

this.aBarMethod();

(Dove this è usa e getta ma mi piace e sembra che piaccia anche a te.) Poiché Foo eredita aBarMethod , in realtà appartiene a this quindi riferirsi ad esso tramite this rende perfetti senso. Solo se vuoi davvero disabilitare la spedizione dinamica, fai riferimento ad essa tramite super . Un caso d'uso comune (anche se di stile discutibile) è se si desidera estendere un metodo che non è stato progettato per questo. Ad esempio, potresti aggiungere al metodo toString della tua super classe.

class Base {
    @Override
    public String toString() {
        return "base";
    }
}

class Derived extends Base {
    @Override
    public String toString() {
        return super.toString() + " & derived";
    }
}

Chiamare toString su un oggetto Derived genererà "base & derived" .

Personalmente, mi sento sempre sporco se uso la parola chiave super nel mio codice Java. L'unica eccezione è chiamare il costruttore super-classe tramite super(…) , che va bene. A volte, se ignorare i metodi toString , equals , hashCode e clone ereditati da java.lang.Object utilizzando super (come nell'esempio precedente) è difficile da evitare.

1 Fare ciò è generalmente una buona idea. Alcune persone, incluso me, preferiscono rendere qualsiasi metodo astratto, definitivo o vuoto. Esiste anche una regola del controllo stile per far rispettare questa regola. Se sei preoccupato per uno stile di codifica valido e coerente, probabilmente ti piacerà Checkstyle se non lo stai già utilizzando.

    
risposta data 03.04.2015 - 02:03
fonte
0

Non sono sicuro di Java, ma C # ha un intero insieme di linee guida per la progettazione della struttura , che include convenzioni di denominazione per membri pubblici e protetti. I campi protetti non sono raccomandati. Utilizza invece le proprietà protette.

    
risposta data 03.03.2015 - 21:17
fonte

Leggi altre domande sui tag