View Full Version : [Programmazione Object Oriented] Buone norme..
Salve,
volevo sapere quali sono le buone norme di programmazione object oriented.
Intendo dire:
è bene che una classe abbia un costruttore non void all'interno del quale chiama i vari metodi (propri della classe) che inizializzano i diversi attrbuti private dalla classe.
Questi metodi in base al tipo di parametri passati al costrutture non void inizializzano gli attributi della classe in modo diverso.
Vengono chiamati in un'ordine preciso, altrimenti il programma crasha per Segmentation Fault in quanto il metodo 2 lavora sugli attributi inizializzati dal metodo 1 e cosi via.
Non chiedo questo perchè non mi gira il programma, ma bensi per far si che il codice che sto producendo sia il + mantenibile e il -caotico possibile.
Classe A {
private:
attributo 1; //puntatore a dato da allocare dinamicamente tramite metodo1
attributo 2;
public A(parametro){
metodo1(parametro);
metodo2();
//questo è l'ordine preciso in cui i due metodi devono essere chiamati
// altrimenti a run time metodo2 che lavora su attributo1 (che ad es è un puntatore)
// fa crashare il programma per segmentation fault in quanto l'attributo
// non è stato allocato dinamicamente
}
private metodo1(p){...};
private metodo2(){...};
}
è bene che una classe abbia un costruttore non void all'interno del quale chiama i vari metodi (propri della classe) che inizializzano i diversi attrbuti private dalla classe.
Il costruttore non ha tipo di ritorno quindi non esiste costruttore void o non void.
Poi va bene inizializzare le variabili di istanza di un oggetto con il costruttore, è l'utilizzo classico.
Nel tuo caso specifico però non ho chiara la situazione e quindi non posso darti altre soluzioni.
Ciao
franksisca
08-11-2005, 10:12
allora, per buona norma una classe ben progettata deve aver un:
toString();
equals();
compareTo();
le variabili private e i metodi di accesso alle variabili set e get.
Per altre specifiche, non credo siano necessarie, al massimo ti consiglio di implementare cloneable e ridefinire il metodo clone();.
end.is.forever
08-11-2005, 10:21
allora, per buona norma una classe ben progettata deve aver un:
toString();
equals();
compareTo();
Stai scherzando vero? :D
franksisca
08-11-2005, 10:44
forse ho dimenticato di specificare in java :D :D :D
perchè in JAVA è così
akfhalfhadsòkadjasdasd
08-11-2005, 10:59
allora, per buona norma una classe ben progettata deve aver un:
toString();
equals();
compareTo();
le variabili private e i metodi di accesso alle variabili set e get.
Per altre specifiche, non credo siano necessarie, al massimo ti consiglio di implementare cloneable e ridefinire il metodo clone();.
questo è lo stato dell'arte :O (buono per l'esame ;) )
franksisca
08-11-2005, 11:03
buono per l'esame ;)
:D :D :D
end.is.forever
08-11-2005, 11:14
perchè in JAVA è così
Ma in nessun linguaggio :)
allora, per buona norma una classe ben progettata deve aver un:
Una classe ben progettata deve fare nulla di piu' di quello che le e' richiesto, in qualunque linguaggio :)
Quindi se toString() non e' richiesto, non lo si scrive. Se per l'oggetto non ha senso essere clonato, non si implementa Cloneable. E cosi' via...
franksisca
08-11-2005, 11:24
Ma in nessun linguaggio :)
:mbe: :mbe: :mbe: Non capisco cosa vuoi dire, magari in altri linguaggi non si chiamano in quel modo, ma il significato credo che sia da esplicitare in ogni oggetto, q eusto prp:
equals = ritorna tru se l'oggetto chiamato (a) è uguale all'oggetto chiamante (b), in java a.equals(b)
compareTo = ritorna un intero che individua l'ordine degli oggetti, sempre in java:
a.compareTo(b) =1 se a>b, =-1 se b>a, =0 se aè=b;
il toString() stampa l'oggetto.
Ripeto, in java si chiamano così, ma credo che siano delle otttime regole di lavoro ad oggetto.
franksisca
08-11-2005, 11:26
Una classe ben progettata deve fare nulla di piu' di quello che le e' richiesto, in qualunque linguaggio :)
Quindi se toString() non e' richiesto, non lo si scrive. Se per l'oggetto non ha senso essere clonato, non si implementa Cloneable. E cosi' via...
Vero, naturalmente, ma se mi vengono chiesti degli standard di scrittura di un oggetto, io quelli ce li metto sempre, anche se non mi servono, tanto non mi rubano più di 5 minuti, e se li guarderà qualcun'altro almeno qualcosa di comprensibile ci sarà. :rolleyes:
end.is.forever
08-11-2005, 11:31
:mbe: :mbe: :mbe: Non capisco cosa vuoi dire, magari in altri linguaggi non si chiamano in quel modo, ma il significato credo che sia da esplicitare in ogni oggetto, q eusto prp:
equals = ritorna tru se l'oggetto chiamato (a) è uguale all'oggetto chiamante (b), in java a.equals(b)
compareTo = ritorna un intero che individua l'ordine degli oggetti, sempre in java:
a.compareTo(b) =1 se a>b, =-1 se b>a, =0 se aè=b;
il toString() stampa l'oggetto.
Ripeto, in java si chiamano così, ma credo che siano delle otttime regole di lavoro ad oggetto.
Non sono norme di programmazione, sono particolari interfacce, quindi caratteristiche che alcuni elementi possono avere altri no.
Il metodo equals lo implementi quando per qualche ragione hai bisogno di confrontare due istanze di quella classe, compareTo quando le istanze di quella classe possono essere associate ad un insieme ordinato, toString (e ancora più raro) quando ti serve una rappresentazione sotto forma di stringa dell'istanza (quest'ultimo poi non lo si usa quasi mai, essendo inadatto a pattern di costruzione delle stringhe efficienti, e poi perchè molto spesso si preferisce delegare a classi apposite la conversione dato che non necessariamente è responsabilità della classe stessa).
Posso condividere il get dei campi privati, per il set già sono meno d'accordo, se hai un campo che è scrivibile e leggibile tanto vale che sia pubblico.
Questo a meno che tu non abbia bisogno di fare qualcosa al momento della scrittura/lettura, e anche qui (come per i 3 metodi di cui parli) si tratta sempre di casi particolari e non di norme.
Vero, naturalmente, ma se mi vengono chiesti degli standard di scrittura di un oggetto, io quelli ce li metto sempre, anche se non mi servono, tanto non mi rubano più di 5 minuti, e se li guarderà qualcun'altro almeno qualcosa di comprensibile ci sarà. :rolleyes:
Se un coding standard ti richiede di scrivere metodi anche se non ti servono non e' un buon coding standard e va modificato.
"L'unica riga di codice senza bug e' quella che non scrivi".
Non sono solo i 5 minuti che perdi per classe (che poi per 10 classi significano 50 minuti che puoi spendere magari semplificando il codice, per 100 classi sono gia' 500 minuti, quasi 10 ore, piu' di una giornata di lavoro). Quei metodi li paghi in termini di manutenzione del codice: se cambi qualcosa e il metodo che non usi non compila? lo devi modificare ad esempio; e se cambi l'implementazione della casse? devi cambiare anche quei metodi per riflettere la nuova implementazione, anche se non li usi da nessuna parte; e se li lasci scorretti? che senso avrebbe avere un'implementazione scorretta, nessuno.
Il codice deve esprimere solo e unicamente i concetti che servono alla risoluzione del problema e nient'altro.
Posso condividere il get dei campi privati, per il set già sono meno d'accordo, se hai un campo che è scrivibile e leggibile tanto vale che sia pubblico.
Per buona norma e' sempre e comunque preferibile disaccoppiare i campi attraverso propert get/set, tanto che in linguaggi come C# questa norma e' diventata un costrutto del linguaggio.
La ragione e' disaccoppiare la semantica della proprieta' (ad esempio un contatore in una classe) dall'implementazione della proprieta' stessa (una variabile, oppure magari un ciclo, o quant'altro).
Disaccoppiare l'"interfaccia" dall'implementazione e' sempre una buona idea, perche' riduce gli errori.
Alcuni coding standard portano questo discorso al limite e richiedono che anche i campi privati (e non solo quelli pubblici) siano esposti attraverso property get/set.
:mbe: :mbe: :mbe: Non capisco cosa vuoi dire, magari in altri linguaggi non si chiamano in quel modo, ma il significato credo che sia da esplicitare in ogni oggetto, q eusto prp:
Come implementeresti compareTo() per una classe Complex che rappresenta numeri complessi? :)
Non per tutti gli oggetti (anzi per pochissimi, e per la precisione i value type ordinabili) ha senso un'operazione di comparazione.
franksisca
08-11-2005, 11:39
Se un coding standard ti richiede di scrivere metodi anche se non ti servono non e' un buon coding standard e va modificato.
"L'unica riga di codice senza bug e' quella che non scrivi".
Non sono solo i 5 minuti che perdi per classe (che poi per 10 classi significano 50 minuti che puoi spendere magari semplificando il codice, per 100 classi sono gia' 500 minuti, quasi 10 ore, piu' di una giornata di lavoro). Quei metodi li paghi in termini di manutenzione del codice: se cambi qualcosa e il metodo che non usi non compila? lo devi modificare ad esempio; e se cambi l'implementazione della casse? devi cambiare anche quei metodi per riflettere la nuova implementazione, anche se non li usi da nessuna parte; e se li lasci scorretti? che senso avrebbe avere un'implementazione scorretta, nessuno.
Il codice deve esprimere solo e unicamente i concetti che servono alla risoluzione del problema e nient'altro.
Sono d'accordo, infatti io molte volte non li uso, ma si parlava di standard.
Ora vi faccio un esempio:
Lo standard di progettazione di un software è questo(molto semplificato) diagramma UML,relazione e manuali, Implementazione, testing e pubblicazione.
Ora dimmi, fek, tu che sei un esempio per molti di noi, se tu nella tua vita lavorativa hai seguito questo sviluppo.
Io personalmente, ancora no, ma ritengo che come standard di progettazione vada bene.
ora, la stessa cosa succede per gli oggetti, almeno credo.
se devo fare un programma di inserimento in un database, è logico che il toString non lo uso, ma se mi chiedi come standard se ce lo metto, io allora ti rispondo di si, che come buona regola lo metterei.
Sono d'accordo, infatti io molte volte non li uso, ma si parlava di standard.
Ora vi faccio un esempio:
Lo standard di progettazione di un software è questo(molto semplificato) diagramma UML,relazione e manuali, Implementazione, testing e pubblicazione.
Ora dimmi, fek, tu che sei un esempio per molti di noi, se tu nella tua vita lavorativa hai seguito questo sviluppo.
No, perche' questa metodologia di sviluppo (Waterfall) e' tutto fuorche' efficiente. Anzi, e' un metodo molto costoso, e assolutamente non ottimale, per scrivere codice e costruire software :)
Io personalmente, ancora no, ma ritengo che come standard di progettazione vada bene.
ora, la stessa cosa succede per gli oggetti, almeno credo.
se devo fare un programma di inserimento in un database, è logico che il toString non lo uso, ma se mi chiedi come standard se ce lo metto, io allora ti rispondo di si, che come buona regola lo metterei.
Le buone regole non sono teoriche, sono pratiche e pragmatiche. Una regola e' buona se mi fa risparmiare tempo di sviluppo, mi riduce l'incidenza dei difetti, mi aumenta la produttivita'. Scrivere toString() per tutte le classi anche se non serve, o peggio ancora tale metodo non e' definibile per tale classe, non mi fa risparmiare tempo di sviluppo (anzi), non mi riduce l'incidenza dei difetti (anzi), non mi aumenta la produttivita' (anzi).
Inoltre non segue la regola d'oro della programmazione: "Keep it simple". Ricorda che programmare significa gestire la complessita' di una soluzione, mantenerla al minimo, e vuoi evitare tutto cio' che aumenta questa complessita' e non ti permette di gestirla.
Scrivere codice non utilizzato aumenta la complessita' di una soluzione e come tale non e' una buona regola di programmazione.
In parole povere, se non ti servono, non devi scrivere quei metodi. Questa e' una buona regola di programmazione :)
franksisca
08-11-2005, 11:50
No, perche' questa metodologia di sviluppo (Waterfall) e' tutto fuorche' efficiente. Anzi, e' un metodo molto costoso, e assolutamente non ottimale, per scrivere codice e costruire software :)
E io sono daccordo, ma in tutti i corsi di progettazione software è wuello considerato "migliore".
In parole povere, se non ti servono, non devi scrivere quei metodi. Questa e' una buona regola di programmazione :)
E anche qui sono daccordo, ma ripeto, come regole di buona programmazione io le scriverei comunque, è vero che magari non le usano e mi inducono ad errore, ma se sbaglio un toString, o uno dei simili, che a livello di programmazione non sono niente di complicato(confronti e stampa di variabili interne), credo che la quantità d'errore sia davvero minima.
allora, per buona norma una classe ben progettata deve aver un:
toString();
equals();
compareTo();
le variabili private e i metodi di accesso alle variabili set e get.
Per altre specifiche, non credo siano necessarie, al massimo ti consiglio di implementare cloneable e ridefinire il metodo clone();.
Non hanno senso per tutte le classi quindi non è vero che debbano essere sempre implementati...
E io sono daccordo, ma in tutti i corsi di progettazione software è wuello considerato "migliore".
Sbagliano :)
E anche qui sono daccordo, ma ripeto, come regole di buona programmazione io le scriverei comunque, è vero che magari non le usano e mi inducono ad errore, ma se sbaglio un toString, o uno dei simili, che a livello di programmazione non sono niente di complicato(confronti e stampa di variabili interne), credo che la quantità d'errore sia davvero minima.
Davvero minima e' comunque diverso da zero.
Proviamo un discorso piu' pragmatico: mi dici quali di queste variabile la pratica di scrivere quei metodi anche quando non servono abbassa? Costo, tempo di sviluppo, numero di difetti.
Se una pratica mi abbassa uno di questi numeri, io sono felicissimo di attuarla. Altrimenti no.
In altre parole, se ti serve un mezzo per andare dal lavoro a casa, che distano cinque chilometri, ti compri una bicicletta, una macchina o un elicottero? Nella vita reale tu paghi qualcosa che non usi e che sai che non ti serve?
E' la stessa cosa nel codice: dammi un buon motivo per pagare qualcosa in termini di tempo e io pago. Altrimenti non pago. "Perche' si fa cosi'" non e' un buon motivo.
end.is.forever
08-11-2005, 11:58
La ragione e' disaccoppiare la semantica della proprieta' (ad esempio un contatore in una classe) dall'implementazione della proprieta' stessa (una variabile, oppure magari un ciclo, o quant'altro).
Quando dico "sono meno d'accordo" intendo che già dipende di più dalle situazioni, non che non vada usato.
E anche qui sono daccordo, ma ripeto, come regole di buona programmazione io le scriverei comunque, è vero che magari non le usano e mi inducono ad errore, ma se sbaglio un toString, o uno dei simili, che a livello di programmazione non sono niente di complicato
Come dicevo sopra non per tutte le entità che una classe rappresenta questi metodi hanno un senso...e se non lo hanno è probabilissimo che scrivere quei metodi non sia solo difficile, ma anche fuorviante...
Ad esempio... Una classe che genera numeri pseudocasuali (il numero generato non è contenuto all'interno della classe)...
franksisca
08-11-2005, 12:00
credo che forse sia perchè sono abituato ad una fase di testing da consol, ad una fase di testing sui dati che mi servono, e forse perchè non ho mai avuto un progetto davvero grosso per le mani.
Comunque, è vero che non le diminuiscono, ma il loro aumento è quais pari a zero, e per una eventuale fase di debug da console(io faccio quella, e magari sbaglio, nn lo metto in dubbio), mi trovo metodi di accesso e di controllo sui dati molto rapidi.
Quando dico "sono meno d'accordo" intendo che già dipende di più dalle situazioni, non che non vada usato.
Si', lo capisco e sono parzialmente d'accordo con te :)
Io faccio un discorso un po' piu' generale. L'unico caso in cui posso capire il non proteggere un campo e' l'uso di value type che sono strettamente dati, ad esempio un descrittore:
(C++)
struct CreationFlags
{
bool Flag1;
bool Flag2;
int NumberOfSomething;
};
...
CreationFlags flags;
flags.Flag1 = true;
...
something.Create(flags);
In un caso cosi' sarebbe davvero troppo richiedere un Get/Set per ogni proprieta'. Ma non tutti sono d'accordo con me qui.
In tutti gli altri casi i campi pubblici vanno sempre protetti.
Comunque, è vero che non le diminuiscono, ma il loro aumento è quais pari a zero, e per una eventuale fase di debug da console(io faccio quella, e magari sbaglio, nn lo metto in dubbio), mi trovo metodi di accesso e di controllo sui dati molto rapidi.
Come ho detto, quasi pari a zero non vuol dire zero.
Di nuovo l'esempio dell'andare da casa al lavoro, compreresti l'elicottero perche' magari un giorno ti potrebbe servire per andare in Sardegna? Oppure una bicicletta o una macchina che costano meno?
franksisca
08-11-2005, 12:09
Si', lo capisco e sono parzialmente d'accordo con te :)
Io faccio un discorso un po' piu' generale. L'unico caso in cui posso capire il non proteggere un campo e' l'uso di value type che sono strettamente dati, ad esempio un descrittore:
(C++)
struct CreationFlags
{
bool Flag1;
bool Flag2;
int NumberOfSomething;
};
...
CreationFlags flags;
flags.Flag1 = true;
...
something.Create(flags);
In un caso cosi' sarebbe davvero troppo richiedere un Get/Set per ogni proprieta'. Ma non tutti sono d'accordo con me qui.
In tutti gli altri casi i campi pubblici vanno sempre protetti.
:D :D :D IO SONO DACCORDO :D :D :D
In tutti gli altri casi i campi pubblici vanno sempre protetti.
Concordo...tra l'altro è alla base dell'information hiding...
Non lasciare campi pubblici e permettere l'accesso ai campi privati con metodi setter e getter permette una maggiore manutenibilità del codice...
Pensate se la struttura interna di una classe dovesse cambiare radiacalmente dopo la sua prima implemntazione... Se la variabile pubblica non avesse più senso senza doverla elaborare ci troveremmo di fronte ad un grosso problema per chi accede a quella variabile (cambiare il nome alla variabile e modificare tutte le occorrenze e l'uso nel codice)...
Ad esempio una classe Angolo... Si espone una variabili pubblica gradi...
Ad un certo punto però i calcoli li vogliamo fare in radianti... Dobbiamo quindi convertire la variabile gradi in radianti per ogni metodo della classe che la usa...
Se si usano i metodi setGradi e getGradi, possiamo implementare una conversione all'interno di questi metodi, modificando la rappresentazione interna in radianti...
Quindi io sono per nessun membro pubblico...
Quindi io sono per nessun membro pubblico...
Per la necessità di implementare tutti i setter e i getter...anche qui, mi limito ad implementare quelli che servono all'esterno...
In linguaggi come Ruby, tutti i campi pubblici passano automaticamente attraverso set/get e l'interprete li scrive per te per implementazioni banali :D
In Diamonds usiamo un check che non permette i commit se un campo di una qualunque classe e' pubblico.
Questa pratica si paga in termini di tempo necessario a scrivere i metodi di accesso, ma garantisce un numero minore di difetti. Si paga per avere qualcosa in cambio.
Per la necessità di implementare tutti i setter e i getter...anche qui, mi limito ad implementare quelli che servono all'esterno... Senza contare che non tutti i membri privati hanno un senso per l'esterno...della serie...la variabile è mia (della classe) e me la gestisco come mi pare...
Inoltre una volta implementati tutti i setter ed i getter, ma voglio rivoluzionare la rappresentazione interna della classe devo modfiicarli per renderli compatibili con la rappresentazione attuale (mantendo gli stessi nomi dei metodi) ed aggiungere i setter ed i getter per la nuova struttura interna...
Quindi non solo mi sembra controproducente mettere un set ed un get per ogni variabile privata, ma addirittura assurdo, soprattutto in uno sviluppo di team in cui l'interfaccia della classe deve rimanere il più possibile costante...
Quindi non solo mi sembra controproducente mettere un set ed un get per ogni variabile privata, ma addirittura assurdo, soprattutto in uno sviluppo di team in cui l'interfaccia della classe deve rimanere il più possibile costante...
Guarda, Scott Meyers non e' d'accordo con te :D
http://www.amazon.com/exec/obidos/tg/detail/-/0201924889/103-3864829-8284649?v=glance
(Io sono d'accordo con te)
La logica dietro quello che dice Meyers pero' e' molto sensata, perche' il suo scopo e' disaccoppiare sempre e comunque interfaccia (anche interna) dall'implementazione. Inoltre, ogni entita' deve avere accesso al minimo di informazioni che gli serve per lavorare.
E quindi tutti i campi anche privati vanno dietro a get/set, perche' disaccoppi il cliente dalla loro rappresentazione e gli fornisci il minimo delle informazioni che gli servono.
Meyers dice anche che i metodi dell'interfaccia pubblica di una classe in C++ devono essere funzioni libere non friend, sempre per il principio che non devono avere accesso alla rappresentazione interna della classe, e devono essere disaccoppiati dall'implementazione.
Inoltre, dice che i metodi virtuali devono essere sempre privati e delegati da metodi pubblici non virtuali, perche' un metodo virtuale pubblico vuole risolvere due forze contrastanti: da una parte definire l'interfaccia verso l'esterno, dall'altra definire i punti di modifica virtuale per le classi derivate. Secondo il principio che un'entita deve avere una e una sola responsabilita', crei per uno o piu' metodi virtuali, dei metodi non virtuali pubblici (magari esterni) che disaccoppiano l'interfaccia pubblica della classe dai punti di aggancio per le classi derivate.
*pant* *pant*
Tutto questo sproloquio per dire che?
Per dire che se applici alla lettera tutte queste regolette ti ritrovi con codice un po' troppo "bloated" e ampolloso, ma e' buona cosa conoscerle a mio avviso, per poterle applicare quando ti risolvono effettivamente un problema.
E allora io uso metodi get/set per campi privati quando ho bisogno di disaccoppiare il codice interno dall'implementazione, uso metodi pubblici di accesso a metodi virtuali quando voglio disaccoppiare l'interfaccia della classe dai punti di aggancio. Etc etc... Tutto nell'ottica di spendere il meno possibile, perche' sono pigro :D
Il costruttore non ha tipo di ritorno quindi non esiste costruttore void o non void.
Poi va bene inizializzare le variabili di istanza di un oggetto con il costruttore, è l'utilizzo classico.
Nel tuo caso specifico però non ho chiara la situazione e quindi non posso darti altre soluzioni.
Ciao
So ben che il costruttore non ha tipo di ritorno :) intendo dire un costruttore void come Costruttore() senza parametri e Costruttore(parametri vari) non void come costruttore con parametri.
la mia domanda è questa:
ok che va bene inizializzare le variabili nel costruttore, ma il fatto è che sto lavorando a un progetto in cui per inizalizzare le mie variabili all'interno del costruttore devo chiamare dei metodi in un'ordine preciso, altrimenti la classe viene creata in modo sbagliato ... spero di essermi spiegato stavolta.
Quindi il punto è questo: è corretto o no?
un futuro se un mio collega vuole lavorare sulle classi che sto scrivendo e non capisce che nel costruttore prima deve essere chiamato il metodo1 e poi il metodo2 affinchè alcuni campi della classe non rimangano non inizializzati manderà in palla il programma e non capirà perchè non funziona!
Quindi a mia "discolpa" è sufficente che io commenti bene i diversi metodi (compreso il costruttore ovviamente) della mia classe in modo da spiegarne l'utilizzo? Per utilizzo intendo ad esempio l'ordine in cui devono essere chiamati all'interno del costruttore per creare un oggetto che abbia senso per il tipo di problema che voglio risolvere.
Spero di essere stato chiaro.
Non intendevo sollevare un polverone sull'utilizzo dei metodi setter e getter...
:)
akfhalfhadsòkadjasdasd
08-11-2005, 14:52
classico scontro tra mondo accademico e mondo industriale :O
l'opportunita di definire dei get e set e altri metodi di utilità viene dettato sopratutto dal/dai pattern di progettazione (ingegneria del software) che hai deciso di usare e in parte anche a quello che serve il codice che stai scrivendo.
per il discorso della leggibilità del codice... beh non lo so, nessuno può accusare che il mondo accademico produce codice ampolloso e poco leggibile
quella è un arte di una certa fetta di mondo industriale (per quanto riguarda la leggibilità e documentazione) vecchio stampo (10 anni) ma anche videoludico... a vedere certi sorgenti come quake1, quake2, hl2 sono così "essenziali" che senza una precisa (ma assente) documentazione non si capisce assolutamente nulla.
akfhalfhadsòkadjasdasd
08-11-2005, 15:06
la mia domanda è questa:
ok che va bene inizializzare le variabili nel costruttore, ma il fatto è che sto lavorando a un progetto in cui per inizalizzare le mie variabili all'interno del costruttore devo chiamare dei metodi in un'ordine preciso, altrimenti la classe viene creata in modo sbagliato ... spero di essermi spiegato stavolta.
Quindi il punto è questo: è corretto o no?
un futuro se un mio collega vuole lavorare sulle classi che sto scrivendo e non capisce che nel costruttore prima deve essere chiamato il metodo1 e poi il metodo2 affinchè alcuni campi della classe non rimangano non inizializzati manderà in palla il programma e non capirà perchè non funziona!
Quindi a mia "discolpa" è sufficente che io commenti bene i diversi metodi (compreso il costruttore ovviamente) della mia classe in modo da spiegarne l'utilizzo? Per utilizzo intendo ad esempio l'ordine in cui devono essere chiamati all'interno del costruttore per creare un oggetto che abbia senso per il tipo di problema che voglio risolvere.
Spero di essere stato chiaro.
Non intendevo sollevare un polverone sull'utilizzo dei metodi setter e getter...
:)
beh i commenti sicuramente ci vogliono... per me andrebbe pure bene. ce l'hai una gestione delle eccezioni? la classe è molto complessa?
Quindi da quel che mi dici se esiste un'ordine in cui devono essere chiamati i metodi "pseudo-setter"* all'interno del costruttore non è un errore. L'importante è che lo scrivo nella documentazione in modo da facilitare chi poi lavorerà sulla mia classe.
*"pseudo-setter" - metodi che inizializzano più di una variabile e che mi non si chiamano setNomeVariabile ma con un altro nome. La funzione però è simile. Perdonatemi fantasioso dei termini!
Ad esempio nel progetto a cui sto lavorando non ho messo alcun setter, in quanto tutti i metodi (pseudo-setter) che inizializzano variabili li chiamo dal costruttore una volta sola. In altri progetti invece ho scritto il metodo setter e getter per ciascun attributo.. ma è dipeso dal tipo di problema che dovevo risolvere.
In questo progetto alcune classi sono "usa e getta", nel senso che una volta che ho creato l'oggetto, ne stampo il contenuto su file e poi lo dealloco... senza aver necessità di accedere ai campi tramite metodi getter. Uso solo un metodo "print" che stampa in output tutti gli attributi e poi l'output lo ridireziono su file.
Anche qui, alcune norme di ingegneria del software direbbero che è scorretto mettere una stampa in output direttamente nella classe... E' anche in questo caso una cosa solamente terica?
Norme in questione
Le norme in questione infatti dicono che è bene che ci sia un:
PRESENTATION LAYER [interagisce con l'utente e invia i dati in input al business layaer]
BUSINESS LAYER [.. il quale li rielabora e accede alle classi tramite i metodi setter e getter]
DATA LAYER [in cui sn memorizzati gli oggetti dato]
un futuro se un mio collega vuole lavorare sulle classi che sto scrivendo e non capisce che nel costruttore prima deve essere chiamato il metodo1 e poi il metodo2 affinchè alcuni campi della classe non rimangano non inizializzati manderà in palla il programma e non capirà perchè non funziona!
In futuro se il tuo collega deve solo usare la classe, non deve conoscerne il funzionamento interno, non gli serve sapere che il costruttore chiama i metodi privati della classe in un certo ordine. Il contratto della tua classe impone che a seguiro della creazione dell'oggetto (quindi della chiamata al costruttore), l'oggetto e' creato correttamente ed e' usabile, altrimenti avrebbe sollevato un'eccezione.
Non devi neppure commentarlo.
Discorso leggermente diverso se il tuo collega deve "mantenere", quindi modificare la classe che hai scritto tu, quindi deve sapere che il costruttore deve chiamare due metodi in un certo ordine per la corretta creazione della classe.
Come fare?
Una soluzione potrebbe essere commentare il codice, qualcosa del tipo:
[Java]
MyClass()
{
// ...
// method1() dev'essere chiamato prima di chiamare method2()
method1();
method2();
// ...
}
Male, questo codice viola un principio chiamato DRY (Dont Repeat Yourself), esprimi la stessa informazione sull'ordine di chiamata dei metodi in due posti differenti: il commento e il codice. Se cambi l'ordine dei metodi devi anche modificare il commento. Di solito quando per modificare qualcosa, devi anche modificare qualcos'altro, sei di fronte ad un problema che va risolto.
Vediamo questa versione:
[Java]
MyClass()
{
// ...
firstStepOfInitialisation();
secondStepOfInitialisation();
// ...
}
Gia' molto meglio: i nomi dei due metodi chiariscono immediatamente al tuo collega l'ordine di chiamata dei metodi, senza bisogno di alcun commento o di alcuna documentazione. Si dice che il codice si auto documenta.
Che succede se il mio collega e' magari un po' stanco, ha fretta e modifica questo codice in questa maniera?
[Java]
MyClass()
{
// ...
firstStepOfInitialisation();
// ...
}
Ooops, la seconda chiamata e' sparita, l'oggetto non e' creato completamente e magari scopri bug di fronte al tuo cliente durante la dimostrazione del programma. Non e' una bella situazione.
Il problema si risolve testato automaticamente che il primo metodo e' chiamato prima del secondo. Ma questo e' un altro argomento.
beh i commenti sicuramente ci vogliono...
Altamente discutibile :)
"I commenti sono un deodorante per il codice. Meglio eliminare la puzza."
Quindi da quel che mi dici se esiste un'ordine in cui devono essere chiamati i metodi "pseudo-setter"* all'interno del costruttore non è un errore. L'importante è che lo scrivo nella documentazione in modo da facilitare chi poi lavorerà sulla mia classe.
Ovviamente non c'e' nulla di male a richiedere che certi metodi siano chiamati in un certo ordine. Il problema e' come "documentare" questa necessita', ancora meglio come testare automaticamente che questo contratto sia rispettato in tutte le condizioni di utilizzo.
beh i commenti sicuramente ci vogliono...
Hai ragione, senno non sarebbe un forum
per me andrebbe pure bene. ce l'hai una gestione delle eccezioni? la classe è molto complessa?
La gestione delle eccezioni no, perchè una volta creato l'oggetto ne stampo il contentuo e poi lo dealloco subito dopo, senza farci nessun altro calcolo.
L'inizializzazione corretta dell'oggetto dipende dal file passato in input al programma, se non è corretto il programma non inizializza l'oggetto (Eccezione)
se è corretto lo inizializza e poi ne stampa il contenuto.. infine dealloca l'oggetto creato.
Ovviamente non c'e' nulla di male a richiedere che certi metodi siano chiamati in un certo ordine. Il problema e' come "documentare" questa necessita', ancora meglio come testare automaticamente che questo contratto sia rispettato in tutte le condizioni di utilizzo.
Per il testaggio sto utilizzado dei flag booleani, il concetto è questo: se tutti i flag sono true allora l'oggetto è inizializzato corretamente. Ad es: il metodo1 ha bisogno che il flag0 sia inizializzato a true per fare il suo lavoro, e cosi via. Se alla fine esiste almeno un flag false allora l'oggetto è stato creato scorrettamente.
Per il testaggio sto utilizzado dei flag booleani, il concetto è questo: se tutti i flag sono true allora l'oggetto è inizializzato corretamente. Ad es: il metodo1 ha bisogno che il flag0 sia inizializzato a true per fare il suo lavoro, e cosi via. Se alla fine esiste almeno un flag false allora l'oggetto è stato creato scorrettamente.
E' ok, e' una buona strategia. Occhio che pero' rischi di appesantire molto il codice con tante flag e test se la classe si complica.
akfhalfhadsòkadjasdasd
08-11-2005, 16:26
Altamente discutibile :)
"I commenti sono un deodorante per il codice. Meglio eliminare la puzza."
beh può essere come dici tu, ma se non fosse così? me lo puoi dimostrare?
innanzitutto non voglio certo commentare qualcosa che si commenta da se. mettere commenti e crearsi sopratutto una documentazione serve alla manutenzione di grandi applicazioni, serve a te e serve ai colleghi. naturalmente deve essere sempre consistente con la realtà, univoca e precisa. è una cosa che al momento della creazione ti potrebbe stressare ma farla ma credimi e molto probabile che in fututro sia un ottimo incentivo a risparmiare tempo e nervi :D
beh può essere come dici tu, ma se non fosse così? me lo puoi dimostrare?
innanzitutto non voglio certo commentare qualcosa che si commenta da se. mettere commenti e crearsi sopratutto una documentazione serve alla manutenzione di grandi applicazioni, serve a te e serve ai colleghi. naturalmente deve essere sempre consistente con la realtà, univoca e precisa. è una cosa che al momento della creazione ti potrebbe stressare ma farla ma credimi e molto probabile che in fututro sia un ottimo incentivo a risparmiare tempo e nervi :D
Si', posso dimostrarti quello che dico :)
Versione numero 1:
[C++]
// ...
// Send all directional lights to the GPU
for (s32 i = 0; i < ret_num_directional_lights; ++i)
{
// Get Directional light from the lighting manager and cast it
const CLightingManager::CDirectionalLight* p_directional_light = STATIC_CAST(const CLightingManager::CDirectionalLight*,light_list[ i ]);
// Get direction from the light
CVector3 direction = p_directional_light->GetDirection();
// Get light colour
CRGBFloatColour colour = p_directional_light->GetColour();
// Send direction constant to the GPU
CShaderManager::SetPSConstantElement(BIND_PS_CONSTANT(g_DirectionalLightDirection), element, direction);
// Send colour to the GPU
CShaderManager::SetPSConstantElement(BIND_PS_CONSTANT(g_DirectionalLightColor), element, CVector3(colour.R, colour.G, colour.B));
// next element
element++;
}
// ...
Bel codice, ben commentato vero? No, fa schifo.
Guarda questa versione:
[C++]
// ...
SendDirectionalLightsToTheGPU();
Il nome del metodo si auto commenta.
E poi l'implementazione:
for (s32 i = 0; i < ret_num_directional_lights; ++i)
{
const CLightingManager::CDirectionalLight* light = GetDirectionaLight(i);
light.SendDirectionToTheGPU();
light.SendColourToTheGPU();
light.NextElement();
}
Neppure un commento, ma il codice si commenta da solo.
Regola generale: Non si commenta mai cio' che puo' essere espresso in codice, si commenta solo cio' che non puo' essere espresso in codice.
Quello che il codice fa puo' essere espresso dal codice stesso, che e' la migliore e piu' aggiornata documentazione di se' stesso. Bisogna commentare ad esempio assunzioni che si fanno su un algoritmo ("Questo codice funziona se l'input e' di questo tipo"), oppure post e pre condizioni che non possono essere espresse da assert o da test (rarissimo).
Sostanzilamente, se il codice e' chiaro e ben scritto non c'e' quasi mai necessita' di commentare. Se il codice e' scritto male, la soluzione non e' commentarlo (il deodorante), ma riscriverlo in maniera comprensibile (eliminare la puzza).
"An heuristic we follow is that whenever we feel the need to comment something, we write a method instead" - Martin Fowler
Non commentare, riscrivi il codice, il tuo programma e i tuoi colleghi ti ringrazieranno e tu risparmierai un sacco di tempo :)
E per chi e' curioso, Martin aggiunge:
"Don't worry, we aren't saying that people shouldn't write comments. In our olfactory analogy,comments aren't a bad smell; indeed they are a sweet smell.The reason we mention comments here is that comments often are used as a deodorant. It's surprising how often you look at thickly commented code and notice that the comments are there because the code is bad. ......Our first action is to remove the bad smells by refactoring. When we're finished, we often find that the comments are superfluous."
akfhalfhadsòkadjasdasd
08-11-2005, 17:50
Neppure un commento, ma il codice si commenta da solo.
Regola generale: Non si commenta mai cio' che puo' essere espresso in codice, si commenta solo cio' che non puo' essere espresso in codice.
Quello che il codice fa puo' essere espresso dal codice stesso, che e' la migliore e piu' aggiornata documentazione di se' stesso. Bisogna commentare ad esempio assunzioni che si fanno su un algoritmo ("Questo codice funziona se l'input e' di questo tipo"), oppure post e pre condizioni che non possono essere espresse da assert o da test (rarissimo).
da un punto di vista globale una cosa testimonia sempre la sua funzione. diciamo pure che è una proprietà intrinseca, e su quel che dici non ci piove. dal puto di vista "del comune mortale perso nell'immenso di tutto del codice" le cose che si riescono a capire subito certamente è inutile commentare e questo l'ho anche detto. infatti ho detto che il commento ci voleva in caso (eccezione che conferma la regola) il codice lì è un po' debole ma va bene
Sostanzilamente, se il codice e' chiaro e ben scritto non c'e' quasi mai necessita' di commentare. Se il codice e' scritto male, la soluzione non e' commentarlo (il deodorante), ma riscriverlo in maniera comprensibile (eliminare la puzza).
"An heuristic we follow is that whenever we feel the need to comment something, we write a method instead" - Martin Fowler
Non commentare, riscrivi il codice, il tuo programma e i tuoi colleghi ti ringrazieranno e tu risparmierai un sacco di tempo :)
ma, se hai tempo si, se non sei portato a programmare e scrivere codice perfetto lasciaci stare, oppure trova un compromesso fai una puzzetta lieve qui e li se vedi che nell'intimo della tua classe te lo puoi permettere :D :D :D
da un punto di vista globale una cosa testimonia sempre la sua funzione. diciamo pure che è una proprietà intrinseca, e su quel che dici non ci piove. dal puto di vista "del comune mortale perso nell'immenso di tutto del codice" le cose che si riescono a capire subito certamente è inutile commentare e questo l'ho anche detto. infatti ho detto che il commento ci voleva in caso (eccezione che conferma la regola) il codice lì è un po' debole ma va bene
E' proprio questa la mentalita' sbagliata, dire che il codice un po' debole ma va anche bene, quindi se proprio non si capisce, ci si mette un commento.
No, non funziona cosi'. Il codice un po' debole non va commentato, va riscritto e reso chiaro, perche' tutto il codice deve autocommentarsi. Le eccezioni non devono esserci. E' la sindrome della "broken window".
ma, se hai tempo si, se non sei portato a programmare e scrivere codice perfetto lasciaci stare, oppure trova un compromesso fai una puzzetta lieve qui e li se vedi che nell'intimo della tua classe te lo puoi permettere :D :D :D
Se hai tempo lo fai, se non hai tempo lo fai ugualmente. Se non si e' capaci a scrivere codice leggibile (non perfetto, perche' non esiste), si impara o si cambia mestiere. E' pieno di mestieri in giro :)
Ron Jeffries descrive questo concetto con una metafora divertente: chiama il codice scritto male "coding debt", un debito che si accumula ogni volta che un pezzo di codice e' lasciato li', anche se dovrebbe essere rifattorizzato, e il debito prima o poi viene ripagato in termini di tempo e soldi, fino a che non si accumulano talmente tanti debiti che si va in banca rotta e il progetto non puo' piu' essere concluso.
Si puo' accumulare qualche debito per un breve periodo (magari vicini ad una milestone), ma poi il debito va ripagato subito, e il codice rifattorizzato, riscritto, corretto, semplificato. Le puzzette nella code base devono sparire non appena possibile, non e' una perdita di tempo, e' un guadagno di tempo enorme nel lungo periodo.
Non per altro svariati studi mettono in evidenza come un buon programmatore costi molto meno all'azienda di un programmatore scarso.
akfhalfhadsòkadjasdasd
08-11-2005, 18:13
aiaiaiaiaiaiaiaaiaiaia vabene scomunichiamo il "//" usato ogni tanto ma non mi dirai che HALFLIFE2 si auto commenta da solo appena guardi un metodo!!!!!
aiaiaiaiaiaiaiaaiaiaia vabene scomunichiamo il "//" usato ogni tanto ma non mi dirai che HALFLIFE2 si auto commenta da solo appena guardi un metodo!!!!!
Diamonds si commenta praticamente da solo :)
In futuro se il tuo collega deve solo usare la classe, non deve conoscerne il funzionamento interno, non gli serve sapere che il costruttore chiama i metodi privati della classe in un certo ordine. Il contratto della tua classe impone che a seguiro della creazione dell'oggetto (quindi della chiamata al costruttore), l'oggetto e' creato correttamente ed e' usabile, altrimenti avrebbe sollevato un'eccezione.
Non devi neppure commentarlo.
Discorso leggermente diverso se il tuo collega deve "mantenere", quindi modificare la classe che hai scritto tu, quindi deve sapere che il costruttore deve chiamare due metodi in un certo ordine per la corretta creazione della classe.
Come fare?
Una soluzione potrebbe essere commentare il codice, qualcosa del tipo:
[Java]
MyClass()
{
// ...
// method1() dev'essere chiamato prima di chiamare method2()
method1();
method2();
// ...
}
Male, questo codice viola un principio chiamato DRY (Dont Repeat Yourself), esprimi la stessa informazione sull'ordine di chiamata dei metodi in due posti differenti: il commento e il codice. Se cambi l'ordine dei metodi devi anche modificare il commento. Di solito quando per modificare qualcosa, devi anche modificare qualcos'altro, sei di fronte ad un problema che va risolto.
Vediamo questa versione:
[Java]
MyClass()
{
// ...
firstStepOfInitialisation();
secondStepOfInitialisation();
// ...
}
Gia' molto meglio: i nomi dei due metodi chiariscono immediatamente al tuo collega l'ordine di chiamata dei metodi, senza bisogno di alcun commento o di alcuna documentazione. Si dice che il codice si auto documenta.
Che succede se il mio collega e' magari un po' stanco, ha fretta e modifica questo codice in questa maniera?
[Java]
MyClass()
{
// ...
firstStepOfInitialisation();
// ...
}
Ooops, la seconda chiamata e' sparita, l'oggetto non e' creato completamente e magari scopri bug di fronte al tuo cliente durante la dimostrazione del programma. Non e' una bella situazione.
Il problema si risolve testato automaticamente che il primo metodo e' chiamato prima del secondo. Ma questo e' un altro argomento.
Leggo solo ora questo post in quanto ci si stava rispondendo contemporaneamente, comunque ottimo consiglio! oltre ai commenti (senza ripetermi!) userò nomi di metodi altamente significativi che indichino l'ordine di chiamata.
Thnks!
Leggo solo ora questo post in quanto ci si stava rispondendo contemporaneamente, comunque ottimo consiglio! oltre ai commenti (senza ripetermi!) userò nomi di metodi altamente significativi che indichino l'ordine di chiamata.
Thnks!
Vedrai che con un po' di pratica non ti serviranno neppure piu' i commenti.
akfhalfhadsòkadjasdasd
08-11-2005, 18:40
non hai risposto alla mia domanda, hl2 ha 7 mila file di semplice codice che non si autocommenta affatto senza un minimo supporto di documentazione. tu mi puoi anche dire che si capisce cosa fa un metodo localmente i una classe ma non puoi pretendere che uno nuovo del progetto capisca subito tutto-e-cosa quel pezzo di codice comporta globalmente nel sistema...
Vedrai che con un po' di pratica non ti serviranno neppure piu' i commenti.
non hai risposto alla mia domanda, hl2 ha 7 mila file di semplice codice che non si autocommenta affatto senza un minimo supporto di documentazione. tu mi puoi anche dire che si capisce cosa fa un metodo localmente i una classe ma non puoi pretendere che uno nuovo del progetto capisca subito tutto-e-cosa quel pezzo di codice comporta globalmente nel sistema...
E qui cerco di fare da mediatore:
i commenti li metterò sempre perchè ci sarà sempre il programmatore inesperto che ha bisogno di farsi le ossa e che per iniziare a lavorare e a capire il mio codice ha bisogno di commenti.
Hai mai lavorato a un progetto scientifico di ricerca in cui si implementano algoritmi di difficile comprensione?*
*non immediati e che implichino una conoscenza approfondita di una materia (che sia riguardo la fisica, la biologia, la chimica, l'economica ..)
Be ti assicuro che in questi casi se il programmatore che ha scritto il codice su cui devi lavorare ha aggiunto qualche commento si capisce ben prima la logica del programma senza rompere e far perdere tempo ai Biologi, Economi o chi altri con cui lavori per capire il codice.
Quindi la mia teoria è:
un codice va ben commentato,
troppi commenti vanno evitati se si può fare codice autoesplicativo (con nomi significativo), ma un minimo di commenti (ben ordinati e spiegati) ci vuole.
PS: si lavora in team! mai da soli! E un team non può essere composto da super-programmatori sempre esperti - in un team ci può essere sempre chi ha bisogno di farsi le ossa. Altrimenti come fai ad imparare?
non hai risposto alla mia domanda, hl2 ha 7 mila file di semplice codice che non si autocommenta affatto senza un minimo supporto di documentazione. tu mi puoi anche dire che si capisce cosa fa un metodo localmente i una classe ma non puoi pretendere che uno nuovo del progetto capisca subito tutto-e-cosa quel pezzo di codice comporta globalmente nel sistema...
Ti ho risposto alla domanda. Il codice di Diamonds si auto commenta praticamente tutto, aprilo e guardalo. Se non ti e' chiara l'interfaccia di una classe, ci sono i test relativi che la documentano. Se non ti sono chiare le relazioni fra le varie classi, anche qui ci sono i test che le documentano.
Se qualcosa ancora non e' chiaro, diccelo che semplifichiamo e chiariamo il codice.
Se il codice di HL2 non si auto commenta non e' un problema mio ma di chi lo ha scritto e lo deve mantenere.
Hai mai lavorato a un progetto scientifico di ricerca in cui si implementano algoritmi di difficile comprensione?*
No, ma ho lavorato su code base di qualche milione di righe di codice e so che vuol dire avere codice mal scritto e doverlo studiare :)
Quando hai di fronte un metodo da 1.500 righe, non c'e' commento che tenga. Non si capisce comunque nulla.
un codice va ben commentato,
troppi commenti vanno evitati se si può fare codice autoesplicativo (con nomi significativo), ma un minimo di commenti (ben ordinati e spiegati) ci vuole.
Il codice deve auto commentarsi. Codice ben scritto non ha alcun bisogno di commenti.
PS: si lavora in team! mai da soli! E un team non può essere composto da super-programmatori sempre esperti - in un team ci può essere sempre chi ha bisogno di farsi le ossa. Altrimenti come fai ad imparare?
Pair Programming e Peer Review :)
I programmatori inesperti imparano leggendo codice ben scritto, programmando con chi e' piu' esperto. Tutto possiamo dire di Diamonds ma non che e' composto da super programmatori sempre esperti, anzi, la maggior parte neppure aveva mai visto Java prima (me compreso). Eppure non abbiamo bisogno di commenti, scriviamo codice pulito ed il tempo di ingresso nel progetto e' praticamente nullo.
Ma dei commenti sull'utilizzo delle classi all'interno di un programma ci vogliono.
O di che cosa fa un certo metodo.
Non puoi scrivere metodochecalcolaloscorediunospettrodopoaverfattoildenoisingdeisegnali()
:)
cmq sono d'accordo sulla autoesplicazione del codice (quando possiblie) ma non voglio ora farne una questione "politica".. ora devo andare.
Ciao
Ma dei commenti sull'utilizzo delle classi all'interno di un programma ci vogliono.
O di che cosa fa un certo metodo.
Non puoi scrivere metodochecalcolaloscorediunospettrodopoaverfattoildenoisingdeisegnali()
:)
Ci sono i test automatici per quello :)
Un test ti documenta in maniera inequivocabile il significato e l'uso di un metodo in una classe, oppure la relazione di una classe con un altra. E non solo lo documenta, controlla anche attivamente che i contratti che tu stabilisci e documenti siano effettivamente rispettati dal codice. E lo fa decine di volta al giorno ed e' sempre in sincronia col codice per definizione.
La documentazione e i commenti non sono sempre in sincronia col codice, non controllano attivamente che quello che e' scritto nel commento sia effettivamente vero, non documentano in maniera inequivocabile. Sono una duplicazione di concetti gia' espressi, duplicazione che va mantenuta a costo di tempo e denaro. Non c'e' nulla di peggio di un commento sbagliato, non in sincronia col codice.
Ripeto, guardate il codice di Diamonds, e' disponibile a tutti e non c'e' un commento che sia uno :)
E poi ditemi se non e' piu' che chiaro.
jappilas
08-11-2005, 20:42
Lo standard di progettazione di un software è questo(molto semplificato) diagramma UML,relazione e manuali, Implementazione, testing e pubblicazione.
a parte che per quanto ne so, SW _solution_development_design_model != (coding standard || naming_convention) , cioè è diverso e prescinde
ma una domanda: se anche progettassi la tua soluzione informatica tramite UML, modelleresti le strutture dati sul problema concreto, o, avresti un approccio generale al problema, introducendo classi astratte, implemetandone estensivamente i metodi per farle apparire "complete" e "general purpose", anche se non utili e propedeutici ad un problema, che avrebbe magari preferito una classe meno general purpose e più efficiente?
voglio dire, UML non vuol dire strutturare le classi in modo non mirato...
"I commenti sono un deodorante per il codice. Meglio eliminare la puzza."
i tuoi trattati sul code design e le code smells... dolci ricordi :D
Ripeto, guardate il codice di Diamonds, e' disponibile a tutti e non c'e' un commento che sia uno :) E poi ditemi se non e' piu' che chiaro.
sono mancato per un po' di tempo, non avevo ancora installato Eclipse e ho scaricato l' SVN solo adesso ma... miracolo! mi ci raccapezzo! (cioè, devo solo capire l' organigramma delle stories e cosa si voleva ottenere volta per volta :fagiano: ) :)
comunque è vero, l' optimum a cui si deve tendere è programmare "in inglese", facendo in modo che gli statement sembrino frasi di senso compiuto ;)
jappilas
08-11-2005, 20:54
Ma dei commenti sull'utilizzo delle classi all'interno di un programma ci vogliono.
O di che cosa fa un certo metodo.
Non puoi scrivere metodochecalcolaloscorediunospettrodopoaverfattoildenoisingdeisegnali()
:)
IMHO, solo una categoria di codice, tra quello scritto ex novo (quando si deve riciclare codice altrui è un altro paio di maniche, ma quando si ha il controllo totale non ci sono scusanti) , può permettersi di non essere autoesplicativo (ma allora non ci si potrà esimere dal commentarlo più che bene): quello che presenta un più o meno ingente disaccoppiamento tra funzione, algoritmo e implementazione -
ad esempio, qualora esaminando una funzione e notando che questa va a leggere da una tabella di valori o faccia somme e shift a sinistra (CORDIC), non avessi modo di rendermi conto che si sta calcolando un sin()...
ma qui siamo nel regno delle ottimizzazioni
I programmatori inesperti imparano leggendo codice ben scritto, programmando con chi e' piu' esperto. Tutto possiamo dire di Diamonds ma non che e' composto da super programmatori sempre esperti, anzi, la maggior parte neppure aveva mai visto Java prima (me compreso). Eppure non abbiamo bisogno di commenti, scriviamo codice pulito ed il tempo di ingresso nel progetto e' praticamente nullo.
Io sono un esempio pratico di programmatore inesperto che guardando diamonds ci capisce tutto (ok, ok...sto scherzando, la parte dell'opengl l'ho guardata :stordita: , ma lì è perchè non conosco le librerie), e conoscenza generale nella programmazione non dico sia pari a nulla, ma comunque oltre ai semplici programmini (calcolatrice in vb, notepad e altre cose simili) non ha mai fatto. Però già il fatto di esser riuscito a fare un task del progetto con relativi test e implementazione scritti da 0 mi soddisfa ^^
Fek, penso che il tuo esempio dei commenti lo farò leggere a qualcuno che conosco (stai pensando a qualche mio prof? ma...come hai fatto? :D ), visto che a parte code del tipo x++ il resto lo vuole commentato
Ehi fek, a quando il tuo libro in tutte le migliori biblioteche? :Prrr:
akfhalfhadsòkadjasdasd
08-11-2005, 21:41
IMHO, solo una categoria di codice, tra quello scritto ex novo (quando si deve riciclare codice altrui è un altro paio di maniche, ma quando si ha il controllo totale non ci sono scusanti) , può permettersi di non essere autoesplicativo (ma allora non ci si potrà esimere dal commentarlo più che bene): quello che presenta un più o meno ingente disaccoppiamento tra funzione, algoritmo e implementazione -
ad esempio, qualora esaminando una funzione e notando che questa va a leggere da una tabella di valori o faccia somme e shift a sinistra (CORDIC), non avessi modo di rendermi conto che si sta calcolando un sin()...
ma qui siamo nel regno delle ottimizzazioni
awwww mi viene il mal di pancia :( :(
:D :D :D :D
akfhalfhadsòkadjasdasd
08-11-2005, 21:48
Ti ho risposto alla domanda. Il codice di Diamonds si auto commenta praticamente tutto, aprilo e guardalo. Se non ti e' chiara l'interfaccia di una classe, ci sono i test relativi che la documentano. Se non ti sono chiare le relazioni fra le varie classi, anche qui ci sono i test che le documentano.
Se qualcosa ancora non e' chiaro, diccelo che semplifichiamo e chiariamo il codice.
Se il codice di HL2 non si auto commenta non e' un problema mio ma di chi lo ha scritto e lo deve mantenere.
ok mi hai convinto in parte, se ci sono meccanismi automatici che permettono di estrarre la conoscenza necessaria dal codice stesso ben vengano...
jappilas
08-11-2005, 21:55
awwww mi viene il mal di pancia :( :(
:D :D :D :D
dalle risate?
ok che non avrò la capacità di spiegare di francesco, a volte dico qualcosa di inesatto,
ma non mi sembrava di scrivere cose così esilaranti... :mbe: :rolleyes:
ok mi hai convinto in parte, se ci sono meccanismi automatici che permettono di estrarre la conoscenza necessaria dal codice stesso ben vengano...
Per Java esistono dei tool che creano i diagrammi di classe a partire dal codice. Vicius ha trovato un plugin per Eclipse.
Per C++/C# c'e' il Visual Studio 2005 che crea un class diagram in automatico.
I diagrammi UML creati automaticamente sono utilissimi come ulteriore punto di vista sul codice.
akfhalfhadsòkadjasdasd
08-11-2005, 23:04
Per Java esistono dei tool che creano i diagrammi di classe a partire dal codice. Vicius ha trovato un plugin per Eclipse.
Per C++/C# c'e' il Visual Studio 2005 che crea un class diagram in automatico.
I diagrammi UML creati automaticamente sono utilissimi come ulteriore punto di vista sul codice.
uml e diagrammi di classe!? se avessimo parlato in questi termini ci saremo risprmiato parecchi post... io quelle cose le intendevo per sottinteso ;)
cmq bella discussione.. ciao!
akfhalfhadsòkadjasdasd
08-11-2005, 23:14
dalle risate?
ok che non avrò la capacità di spiegare di francesco, a volte dico qualcosa di inesatto,
ma non mi sembrava di scrivere cose così esilaranti... :mbe: :rolleyes:
perdonami... no è ulcera... mi viene un attacco automatico di ulcera ogniqualvolta leggo qualcosa di difficile, che non riesco a capire subito! oppure quando compilo e c'è un errore stupido... è peggio ancora quando c'è il segnale acustico di errore... quello e proprio la fine. prendo il calendario e inizio a bestemmiare :mad:
jappilas
08-11-2005, 23:54
perdonami... no è ulcera... mi viene un attacco automatico di ulcera ogniqualvolta leggo qualcosa di difficile, che non riesco a capire subito!
perdonami tu ho pensato fosse un post sarcastico :O :O :O
forse sono più chiaro in questi termini: alle volte si vuole implementare una funzione passando "per vie traverse", cioè adoperando accorgimenti e algoritmi che alla fine fanno sembrare il codice (c/c++) poco simile al risultato finale che ottiene
(ad esempio, se tu vedessi un codice che effettua quache shift qua, qualche somma là, non te la daresti che sta calcolando il seno di un angolo con l' algoritmo CORDIC - il quale a sua volta ha alle spalle il fatto che andando a considerare il campo dei numeri complessi e relativi fase/argomento permette di calcolare le trigonometriche in modo veloce)
in questo caso il codice dubito possa essere autoesplicativo e andrà MOLTO ben documentato (personalmente farei un riassunto della teoria matematica di riferimento)
però siamo in presenza di un' ottimizzazione a livello di implementazione, e magari stiamo leggendo codice che altri hanno fatto... non una funzione nell' ambito di un progetto SW più vasto e su cui abbiamo controllo...
Ci sono i test automatici per quello :)
Esistono test automatici anche per farmi capire il bakground su cui sto lavorando? O se i dati che il programma produce hanno senso rispetto al problema originale?
Esempio:
lavori in un team di ricerca sul DNA con biologi, i biologi con cui lavori ti spiegano il problema. Esso implica conoscenze che un informatico o bioinformatico che sia non può avere complete ( o comunque al medesimo livello di un ricercatore biologo che ha speso una vita per "raccimolarle"..) ecco ora arriva il bello.. il biologo ti spiega un'idea rivoluzionaria che deve essere implementata tramite un sofisticato algoritmo per realizzare un programma utilizzato poi nel mondo della ricerca.
A questo punto tu fek decidi di scrivere il tuo bel codice senza alcun commento. Un giorno ti licenzi e cambi lavoro. Ai tuoi colleghi rimangono i test automatici. Ma seppur capendo benissimo le relazioni tra le diverse classi e l'ordine di chiamata dei metodi non capiscono il perchè di tutto ciò. Per loro il programma produce semplicemente dei numeri e non crasha.
Quindi ora, per capire se il codice che dovranno modificare (per aggiungere ad esempio una variante ottimizzata dell'algoritmo) sta producendo risultati con senso devono avere un'idea di come funziona l'algoritmo a livello biologico, cosa che va al di là del codice autoesplicativo. Cosa per cui ci sono due soluzioni:
- o chiedere più volte ai colleghi biologi la spiegazione dell'algoritmo
- o guardare e cercare di capire il codice sorgente del collega e capire cosi in modo autonomo lo scopo dell'algoritmo.
Quindi sentire parlare di codice totalmente senza commenti mi fa pensare a un contesto di applicazione semplice (intesa come conoscenze extra informatiche necessarie: un gioco, un programma di contabilità ...), ma è ben distante da un contesto scientifico in cui il programma deve servire alla scienza per progredire.
Come può un programmatore capire l'intuizione geniale del suo collega biologo semplicemente guardando il codice privo di commenti del suo collega informatico?
Come può capire che tipo di risultato si aspetta il biologo? E come può capire se il risultato è corretto se nel codice non c'è un minimo di commento a spiegarglielo?
E infine: perchè nei linguaggi di programmazionie più diffusi si implementano i commenti?
Per quanto riguarda Java che stai usando nel progetto Diamonds, se ti è capitato di usare JBuilder o NetBeans, avrai notato che se cerchi sulla reference trovi i javadoc che spiegano l'utilizzo delle classi (API), e avrai anche notato che sono molto ma molto comodi per capirne al volo l'utilizzo. Il java doc è un tipico esempio di documentazione del codice. Ti sfido a capire l'uso di un ActionListener guardando solamente il codice sorgente e senza avere conoscenze di programmazione ad eventi.
Quanto comodo è poter usare il java doc? e quanto tempo e denaro fa risparmiare al programmatore e alla software house? Molto!
Pensati te se i programmatori che hanno scritto le API java non avessero fatto alcun commento javadoc....
Spero di essere stato chiaro, ma è una questione di principio. Senza rancore.
The3DProgrammer
09-11-2005, 00:16
Mi trovo esattamente in questa situazione...sto lavorando ad un engine raytracing, e per migliorarne le performance sto implementando tecniche di spatial subdivision basate su OCTree....sta venendo su bene, a parte un PICCOLO dettaglio....verificare se una bbox e un triangolo overlappano è un casino, e sto utilizzando una funzione trovata sul web che implementa un tale algoritmo...sfortunatamente nel codice nn esiste nemmeno una riga di commento...se da un lato sono grato agli autori per questa soluzione (nn credo ci sarei mai riuscito da solo) dall'altro qualke bestemmiuccia se la sono presa, xkè ovviamente dal codice nn ci capisco una mazza:D
ciauz
Mi trovo esattamente in questa esitazione...sto lavorando ad un engine raytracing, e per migliorarne le performance sto implementando tecniche di spatial subdivision basate su OCTree....sta venendo su bene, a parte un PICCOLO dettaglio....verificare se una bbox e un triangolo overlappano è un casino, e sto utilizzando una funzione trovata sul web che implementa un tale algoritmo...sfortunatamente nel codice nn esiste nemmeno una riga di commento...se da un lato sono grato agli autori per questa soluzione (nn credo ci sarei mai riuscito da solo) dall'altro qualke bestemmiuccia se la sono presa, xkè ovviamente dal codice nn ci capisco una mazza:D
ciauz
Mal comune mezzo gaudio! Anche se in un contesto diverso.
Ho, anzi abbiamo, bestemmiato per giorni per capire gli script di un nostro collega. Alla fine (per quanto autoesplicativi fossero i nomi delle variabili e delle funzioni) mi sono dovuto far rispiegare il problema dai biologi-chimici con cui lavoro e ho iniziato l'implementazione del programma da 0! Senza la contestualizzazione ci avrei sbattuto la testa per giorni senza capircene fuori tanto.. :muro:
Non aggiungo nessun altro commento perchè è autoesplicativo il mio post precedente :)
Notte!
The3DProgrammer
09-11-2005, 00:38
Mal comune mezzo gaudio!
Hehe io xò sono stato + fortunato :p
Xkè sono riuscito a capire come integrarlo nel sw, x cui mi accontento di utilizzare senza capire ;)
ciauz
Dipende anche da quanto è buono il codice...
Non sono solo le variabili e le funzioni che devono essere autoesplicative...ma anche il codice deve essere buono... Per buono intendo "scritto bene"...e rispettando delle metriche molto ristrette...
Se ad esempio un metodo è composto da 100 righe (o anche da 50) e nella classe ci sono 50 metodi...è chiaro che diventa complicatissimo, anche se i nomi sono autoesplicativi...
L'esempio di codice fatto di da fek calza a pennello...
Esistono test automatici anche per farmi capire il bakground su cui sto lavorando? O se i dati che il programma produce hanno senso rispetto al problema originale?
Certo, li scrivi :)
Come può un programmatore capire l'intuizione geniale del suo collega biologo semplicemente guardando il codice privo di commenti del suo collega informatico?
Se il codice si auto commenta, e' scritto come se fosse inglese, quindi l'intuizione geniale e' li', chiara, e leggibile, nel codice. Non ha bisogno di alcun commento.
Come può capire che tipo di risultato si aspetta il biologo? E come può capire se il risultato è corretto se nel codice non c'è un minimo di commento a spiegarglielo?
Leggendo il codice ben scritto (se e' ben scritto). Sara' piu' chiaro e formale di qualunque commento in un linguaggio informale come quello naturale.
Ti sei mai domandato perche' i teoremi anche i piu' complessi sono espressi in linguaggi formali e non in linguaggi naturali? Perche' sono piu' semplici da comprendere per chi conosce il linguaggio.
E infine: perchè nei linguaggi di programmazionie più diffusi si implementano i commenti?
Per commentare le assunzioni che non possono essere espresse in codice.
Per quanto riguarda Java che stai usando nel progetto Diamonds, se ti è capitato di usare JBuilder o NetBeans, avrai notato che se cerchi sulla reference trovi i javadoc che spiegano l'utilizzo delle classi (API), e avrai anche notato che sono molto ma molto comodi per capirne al volo l'utilizzo. Il java doc è un tipico esempio di documentazione del codice. Ti sfido a capire l'uso di un ActionListener guardando solamente il codice sorgente e senza avere conoscenze di programmazione ad eventi.
Ora stiamo parlando di documentazione, che e' un concetto totalmente differente da un commento dentro il codice. Non credo che i commenti siano un trattato di programmazione ad eventi.
Spero di essere stato chiaro, ma è una questione di principio. Senza rancore.
Non e' una questione di principio, e' una questione di praticita' e di produttivita'.
Se pensi che i commenti possano migliorare la situazione se il codice e' mal scritto, sbagli. Se pensi che non serva mai commentare, sbagli, serve commentare solo cio' che non puo' essere espresso in codice (come il contratto di un API in un Javadoc).
Esistono linguaggi come Eiffel che documentano anche i contratti in codice, e non hanno bisogno neppure di quei commenti.
Infine: se pensi che davanti a codice mal scritto la soluzione sia commentarlo, sbagli, la soluzione e' riscriverlo.
Mi trovo esattamente in questa situazione...sto lavorando ad un engine raytracing, e per migliorarne le performance sto implementando tecniche di spatial subdivision basate su OCTree....sta venendo su bene, a parte un PICCOLO dettaglio....verificare se una bbox e un triangolo overlappano è un casino, e sto utilizzando una funzione trovata sul web che implementa un tale algoritmo...sfortunatamente nel codice nn esiste nemmeno una riga di commento...se da un lato sono grato agli autori per questa soluzione (nn credo ci sarei mai riuscito da solo) dall'altro qualke bestemmiuccia se la sono presa, xkè ovviamente dal codice nn ci capisco una mazza:D
ciauz
Quel codice era evidentemente mal scritto. Commentarlo non sarebbe stata la soluzione, scriverlo in maniera chiara sarebbe stato molto meglio.
Mal comune mezzo gaudio! Anche se in un contesto diverso.
Ho, anzi abbiamo, bestemmiato per giorni per capire gli script di un nostro collega. Alla fine (per quanto autoesplicativi fossero i nomi delle variabili e delle funzioni) mi sono dovuto far rispiegare il problema dai biologi-chimici con cui lavoro e ho iniziato l'implementazione del programma da 0! Senza la contestualizzazione ci avrei sbattuto la testa per giorni senza capircene fuori tanto.. :muro:
Non aggiungo nessun altro commento perchè è autoesplicativo il mio post precedente :)
Notte!
Stai confondendo la documentazione e la definizione delle specifiche e del dominio del problema con i commenti. Sono cose diverse.
Non credo che dentro il codice del tuo collega ci fosse spazio per un trattato di biologia per farti comprendere il dominio del problema. Il dominio del problema e' descritto in un documento a parte, come i requisiti. Il dominio della soluzione e' descritto invece nel codice.
In Diamonds i requisiti sono descritti nelle Storie e nei task. Il dominio del problema e' invece descritto nel documento di design.
La soluzione e' descritta nel codice e non ha bisogno di commenti perche' il codice e' ben scritto.
akfhalfhadsòkadjasdasd
09-11-2005, 10:30
perdonami tu ho pensato fosse un post sarcastico :O :O :O
forse sono più chiaro in questi termini: alle volte si vuole implementare una funzione passando "per vie traverse", cioè adoperando accorgimenti e algoritmi che alla fine fanno sembrare il codice (c/c++) poco simile al risultato finale che ottiene
(ad esempio, se tu vedessi un codice che effettua quache shift qua, qualche somma là, non te la daresti che sta calcolando il seno di un angolo con l' algoritmo CORDIC - il quale a sua volta ha alle spalle il fatto che andando a considerare il campo dei numeri complessi e relativi fase/argomento permette di calcolare le trigonometriche in modo veloce)
in questo caso il codice dubito possa essere autoesplicativo e andrà MOLTO ben documentato (personalmente farei un riassunto della teoria matematica di riferimento)
però siamo in presenza di un' ottimizzazione a livello di implementazione, e magari stiamo leggendo codice che altri hanno fatto... non una funzione nell' ambito di un progetto SW più vasto e su cui abbiamo controllo...
mmmh in quel caso basterebbe dare alla funzione, che racchiude quel codice, un nome abbastanza significativo, non pensi?
ci sono altri casi in cui purtroppo come dici tu e shang84 il "nome simbolico" potrebbe essere più lungo dello stesso metodo. in quel caso non è tanto problema del codice ma limitazione del programmatore che non sa la teoria matematica/scientifica che sta alla base dell'alg. e per quello c'è un efficace soluzione: te la studi :D
in questo caso il codice dubito possa essere autoesplicativo e andrà MOLTO ben documentato (personalmente farei un riassunto della teoria matematica di riferimento)
float ComputeFastSinWithCORDIC(float )
{
// do your mad stuff here
}
float sin(float x)
{
#ifdef USE_FAST_SIN
return ComputeFastSinWithCORDIC(x);
#else
// use slow sin() here
#endif
}
E anche questa volta non c'e' bisogno di commenti :)
E nel codice c'e' anche il nome dell'algoritmo che e' ben documentato online.
mmmh in quel caso basterebbe dare alla funzione, che racchiude quel codice, un nome abbastanza significativo, non pensi?
ci sono altri casi in cui purtroppo come dici tu e shang84 il "nome simbolico" potrebbe essere più lungo dello stesso metodo. in quel caso non è tanto problema del codice ma limitazione del programmatore che non sa la teoria matematica/scientifica che sta alla base dell'alg. e per quello c'è un efficace soluzione: te la studi :D
Quando un nome e' troppo lungo spesso quel metodo sta cercando di fare troppe cose assieme. E' il sintomo di un problema a monte, il metodo va spezzato in parti piu' coese e semplici da nominare.
Imparare a nominare i metodi diventa anche un tool di verifica del proprio design.
jappilas
09-11-2005, 12:50
float ComputeFastSinWithCORDIC(float )
{
// do your mad stuff here
}
float sin(float x)
{
#ifdef USE_FAST_SIN
return ComputeFastSinWithCORDIC(x);
#else
// use slow sin() here
#endif
}
E anche questa volta non c'e' bisogno di commenti :)
E nel codice c'e' anche il nome dell'algoritmo che e' ben documentato online.
:ave: alla capacita' di sintesi del fek
in effetti personalmente, quando posso mantenere il controllo sul codice, cerco di seguire proprio questo tipo di approccio (per poi essere rimproverato di "ridondanza" da colleghi di qui :rolleyes: ) ;)
il problema e' quando tocca mettere le mai in codice scritto da altri, e si constatano, a parte nomi di variabili e funzioni non autesplicativi, che accorgimenti di livello "ottimizzativo" si mescolano ai dettagli algoritmici in quello che si puo' definire "spaghetti code" di difficile gestibilita'... :(
PS: (un po' ot): ti interessa come approssimare un seno con le tangenti iperboliche? :D
PS: (un po' ot): ti interessa come approssimare un seno con le tangenti iperboliche? :D
Hmmm... boh :p
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.