PDA

View Full Version : Storia di un bug


fek
08-06-2005, 17:43
E' stata una giornata frustrante e mi sfogo con voi perche' odio scrivere i blog :)

Alla fine della storia c'e' anche una lezione banale che ho imparato a mie spese e che condivido.

Ieri ero a caccia di un bug che causava una doppia distruzione di un oggetto 3d che rimane per qualche motivo ancora in giro per il mondo e causa un crash dell'applicazione.

Problema classico, anche la soluzione e' piuttosto classica: si aggiunge un sanity check alla classe e si controlla che la classe sia "sana" sempre prima di usarla. Al primo uso di una classe "malata", il sanity check informa il programmatore che puo' facilmente risolvere il problema alla radice.

Armato di quest'idea scrivo il sanity check e aggiungo il codice necessario in C++:

Prima aggiungo un campo che contenga una firma nota alla classe:


unsigned int mSign;


Inizializzo il campo nel costruttore:


, mSign(MODEL_ENGINE_SIGN)


Scrivo un metodo di test per controllare che l'oggetto sia "sano":


bool ModelInstance::Test(void) const
{
if (MODEL_ENGINE_SIGN != mSign)
{
return false;
}

if (!CheckMatrixSanity(*mModelMatrix))
{
return false;
}

return true;
}


Faccio il check in e vado a dormire, sperando che all'indomani il mio sanity check fallisca indicandomi chi sta "rovinando" il mio oggetto.

Oggi mi piovono addosso alcuni bug totalmente scollegati l'uno dall'altro, oggetti che scompaiono quando sono costruiti, bandiere che non possono piu' essere prese in mano e scompaiono quando non devono.

Ovviamente non collego mentalmente i bug al cambiamento di ieri perche' non hanno apparentemente alcun collegamento logico, visto che quello che il codice che ho aggiunto non ha alcun effetto collaterale, non e' altro che un controllo.

Vi risparmio le 6 ore di ricerche che hanno coinvolto quattro o cinque persone ed un paio di tester per arrivare alla conclusione che si', aggiungere un campo ad una classe, ha causato tre bug apparentemente totalmente scollegati in porzioni del gioco lontane mille miglia e che capitano solo in condizioni particolari, non sono totalmente ripetibili.

Allo stato attuale delle cose, non so il perche' cio' accade, ho dovuto togliere i sanity check perche' i bug "scompaiano" e passero' la serata per capire il perche' e' accaduto, dove sia davvero il bug e perche' quelle righe di codice lo hanno scatenato.

Questa storia mi ha insegnato e confermato tre lezioni importanti:

1) Un cambiamento innocente puo' provocare bug apparentemente completamente scollegati e imprevedibili, che solo adeguato testing puo' scovare: questa volta sono stato relativamente fortunato che i bug erano molto evidenti, ma non saro' sempre cosi' fortunato ed il bug puo' potenzialmente uscire allo scoperto il giorno prima della Gold.

2) Senza scendere nei particolari suppongo (ma non so di preciso), che il bug sia dovuto a qualche campo non iniziallizato: inizializzate tutte le variabili e i campi delle classi quando create l'oggetto per evitare brutte sorprese. C# e linguaggi a piu' alto livello lo fanno per voi. E c'e' un perche'.

3) Il C++ e' potente e flessibile, ma questa potenza e flessibilita' arrivano al costo di ore e ore di debugging alla ricerca di problemi non intuitivi come questo.

Spero che questo post vi sia utile per evitare lunghe nottate di debugging come quella che mi aspetta oggi. Torno a caccia :(

PS. Fare Sanity check spesso e volentierie e' una buona idea comunque.

VICIUS
08-06-2005, 18:49
Mi è capitato due volte di aver a che fare con sti bug assurdi nella mia brevissima cariera. Hai tutta la mia comprensione.

Buona fortuna.

ciao ;)

RaouL_BennetH
08-06-2005, 18:57
Ti metterai e vi metterete sicuramente a ridere confessandovi che è il problema che ho attualmente io con una delle mie piccole applicazioni....solo che, il mio sorgente è lungo si e no 200 righe!!! e cmq non riesco a gestire e a capire ancora con certezza assoluta dove diavolo sta l'errore :muro: :muro:

Dico questo perchè mi rendo conto che, avendo voi a che fare con sw complessi, lunghi e anche con parti "slegate" fra di loro, di certo i mal di testa non vi mancano.

Che ti posso dire, se avessi la possibilità ti manderei qualche mia amica non troppo "pudica" a sollevarti il morale :oink:

fek
08-06-2005, 20:14
Ti metterai e vi metterete sicuramente a ridere confessandovi che è il problema che ho attualmente io con una delle mie piccole applicazioni....solo che, il mio sorgente è lungo si e no 200 righe!!! e cmq non riesco a gestire e a capire ancora con certezza assoluta dove diavolo sta l'errore :muro: :muro:

Sai che non mi piace quando fai il modesto :D

Soprattutto se sapessi che razza di idiozia ho scritto per introdurre il bug.
Ho scritto questa cosa qui all'interno della definizione di una classe in un header file in C++:


#ifdef _DEBUG
std::string name;
#endif


Lo stesso header file e' incluso in due punti diversi del codice con _DEBUG definito e non, quindi due parti diverse del programma non sono d'accordo su come l'oggetto e' strutturato in memoria (con o senza il campo 'name'). E questo causa problemi vari ed eventuali e imprevidibili a distanze siderali.

Lezione del giorno: usare la compilazione condizionale all'interno della definizione di una classe in un header file non e' una buona idea.

Che ti posso dire, se avessi la possibilità ti manderei qualche mia amica non troppo "pudica" a sollevarti il morale :oink:

Io sarei anche d'accordo, la mia ragazza meno. Ritratto, io non sarei d'accordo (caso mai leggesse :p).

DanieleC88
09-06-2005, 16:13
Ah... i problemi con la memoria... che belli! Pensa quando ti trovi con una variabile passata come argomento (puntatore) ad una funzione e che è stata allocata in un'altra funzione e deve essere ridimesionata... ora sto sbattendo la testa su una cosa del genere in C, ma con pochi risultati. :(

^TiGeRShArK^
09-06-2005, 21:10
:D
all'inizio credevo fosse la storia di windows :D:D:D
cmq pure è capitato qualcosa di simile... avevo aggiunto del codice x cercare di capire quale fosse il problema..... e non funzionava più un cazzo!:muro:
Cmq onestamente devo dire ke ASP.NET se scritto utilizzando il Visual Basic è veramente da suicidio.... (soprattutto se 6 un programmatore JAVA CAZZO! :muro: ) :D

CoreDump
10-06-2005, 00:04
Bello sto 3d Fek :D, comunque concordo pienamente su tutti e tre i punti,
ovvero :

1) mi è successa una cosa simile un paio di anni fà, un errore
su un progetto piuttosto grande sotto linux, gdb in mano ci ho messo giorni a capire
dove era il problema, ho dovuto sezionare il programma riga x riga, mai sudato
tanto anche perchè era un progetto di lavoro e il capo stava già facendo
la punta al suo arnese :eek: :D :fagiano:

2) Io lo faccio sempre infatti, basta un puntatore non inizializzato a farti
perdere ore di lavoro, l'ho imparato a mie spese :)

3) Completamente d'accordo, ma non posso fare a meno della libertà di
implementazione che offre il c++, ovviamente imho

ciauz. ;)

ri
10-06-2005, 15:07
Ah... i problemi con la memoria... che belli! Pensa quando ti trovi con una variabile passata come argomento (puntatore) ad una funzione e che è stata allocata in un'altra funzione e deve essere ridimesionata... ora sto sbattendo la testa su una cosa del genere in C, ma con pochi risultati. :(

tradotto?

fek
10-06-2005, 15:24
3) Completamente d'accordo, ma non posso fare a meno della libertà di
implementazione che offre il c++, ovviamente imho

Mi piace questo punto. Perche' non usare la liberta' e la flessibilita' solo dove serve? Si unisce il buono dei due mondi: C/C++ dove serve la flessibilita', Java/C#/Python/Ruby dove la flessibilita' non ti serve, ma vuoi produttivita' e tranquillita'.

Sto entrando nell'ottica che non e' strettamente necessario usare un solo linguaggio per tutto il progetto, ma lo strumento giusto al momento giusto. Poi serve la colla per unire i vari linguaggi.

DanieleC88
10-06-2005, 16:12
tradotto?
Esempio:
int main()
{
tipo * variabile;
altro * test;

chiamatachealloca(&variabile);
chiamatacheaggiunge(&variabile,test);
}

void chiamatachealloca(tipo ** x)
{
x = malloc(grandezza);
}

void chiamatacheaggiunge(tipo ** variabile, altro * test)
{
realloc(*variabile,(sizeof(*variabile)+1)*sizeof(tipo*));
memcpy(&(*variabile)->elemento,&test,sizeof(altro*));
}
Vado a memoria. Era qualcosa di simile.

ri
10-06-2005, 17:49
credimi, l'avevo capito, ma a fatica
e non parlo del concetto, parlo dell'italiano

fek
10-06-2005, 18:04
credimi, l'avevo capito, ma a fatica
e non parlo del concetto, parlo dell'italiano

L'italiano era chiarissimo.

ri
10-06-2005, 18:09
può essere
ma era quantomeno confusa

fek
10-06-2005, 18:15
http://www.albisole.it/inser/images/dacciuntagliologo.jpg

ri
10-06-2005, 18:19
che volevi, che ti dicessi "oh sissis è vero mi son sbagliato scusascusascusa!" solo perchè hai postato?

fek
10-06-2005, 18:49
che volevi, che ti dicessi "oh sissis è vero mi son sbagliato scusascusascusa!" solo perchè hai postato?

No, volevo che ci dessi un taglio e lo voglio tutt'ora.

ri
10-06-2005, 19:03
prima tu :bimbo:

mavalavà

cionci
10-06-2005, 19:12
Basta...mettiamoci un bel . e continuicamo a trattare l'argomento...che era interessante...

CoreDump
10-06-2005, 19:54
Mi piace questo punto. Perche' non usare la liberta' e la flessibilita' solo dove serve? Si unisce il buono dei due mondi: C/C++ dove serve la flessibilita', Java/C#/Python/Ruby dove la flessibilita' non ti serve, ma vuoi produttivita' e tranquillita'.

Sto entrando nell'ottica che non e' strettamente necessario usare un solo linguaggio per tutto il progetto, ma lo strumento giusto al momento giusto. Poi serve la colla per unire i vari linguaggi.

Per colla cosa intenti? una cosa tipo CORBA o piu semplicemente una interazione
se cosi si puo dire tra le diverse componenti di un progetto, tipo che per un
gioco che so un rpg 2d, mi faccio 'interfaccia per la gestione opzioni in
visual basic, il motore in c++ e magari un gestore di aggiornamenti in java :D
Io sono del parere che uno deve usare il linguaggio che meglio si adatta al
progetto, tipo un gestionale in visual basic, un motore grafico in c++ etc.etc.
anche perchè resta il fatto che bisogna poi conoscere tutti i linguaggi e bene
non è che puoi improvvisare :mc: :)

fek
10-06-2005, 20:30
Per colla cosa intenti? una cosa tipo CORBA o piu semplicemente una interazione
se cosi si puo dire tra le diverse componenti di un progetto, tipo che per un
gioco che so un rpg 2d, mi faccio 'interfaccia per la gestione opzioni in
visual basic, il motore in c++ e magari un gestore di aggiornamenti in java :D
Io sono del parere che uno deve usare il linguaggio che meglio si adatta al
progetto, tipo un gestionale in visual basic, un motore grafico in c++ etc.etc.
anche perchè resta il fatto che bisogna poi conoscere tutti i linguaggi e bene
non è che puoi improvvisare :mc: :)

Una prima soluzione puo' essere scrivere diversi tool di un progetto in linguaggi diversi come hai detto tu.

Una soluzione ancora piu' radicale in ambito PC e' COM, ma ancora meglio il suo successore .NET. Lo scopo di .NET e' esattamente il poter scrivere ogni oggetto nel linguaggio che meglio gli si adatta, dove ogni oggetto e' naturalmente esposto ad ogni altro linguaggio nell'ambiente CLR.

In un progetto al quale sto lavorando a tempo perso, ad esempio, stiamo scrivendo alcune parti che si interfacciano alle DirectShow in C++ nativo, che espone alcuni oggetti a piu' alto livello ad uno o piu' clienti scritti in C#, che comunicano con una infrastruttura di rete sempre scritta in C#, ma alcune parti multithreading dell'infrastruttra sono scritte in un linguaggio chiamato Cw (Comega) adattissimo a descrivere oggetti concorrenti. Il piano prevede di scrivere alcuni test automatici in linguaggi ad alto livello come Python/Ruby.

L'idea di base e' di usare il linguaggio piu' adatto a descrivere un oggetto e a risolvere un problema.

fek
10-06-2005, 20:46
E comunque ridendo e scherzando anche ieri ho fatto il check in di un bug fix che ha causato un crash grosso come una casa; ed oggi volevano uccidermi.

Il prossimo che nelle news mi dice che tanto i bug fix non possono far danni a nessuno e fare testing non serve, me lo mangio vivo...

... oppure e' colpa mia e devo imparare a stare piu' attento. Fate quello che vi dico non quello che faccio :(

theClimber
10-06-2005, 22:25
Mi piace questo punto. Perche' non usare la liberta' e la flessibilita' solo dove serve? Si unisce il buono dei due mondi: C/C++ dove serve la flessibilita', Java/C#/Python/Ruby dove la flessibilita' non ti serve, ma vuoi produttivita' e tranquillita'.

Sto entrando nell'ottica che non e' strettamente necessario usare un solo linguaggio per tutto il progetto, ma lo strumento giusto al momento giusto. Poi serve la colla per unire i vari linguaggi.

Concordo. Dai un occhio al pattern http://c2.com/cgi/wiki?AlternateHardAndSoftLayers ci sono alcuni spunti interessanti. I concetti di base alla fine si riducono a questo:

- go ahead and write most of your code in the highest level language you can find.
- when you must, use a profiler and find the slow parts of your program.
- Take those parts, and write them in a lower-level language. (E personalmente aggiungerei : se e solo se non trovi un algoritmo + efficiente !)


Comunque io sarei piu' drastico nel separare i mondi: C/C++/Java/C# da una parte [Ovvio che se poi si parla di device driver o componenti particolarmente critiche, la scelta poi finisce sul C] e Python/Ruby/Smalltalk/Prolog/XSLT/XQuery dall'altra, in quanto i primi sono comunque linguaggi piu' "tradizionali", mentre negli altri ci sono feature utili per fare operazioni specializzate, che nei giusti casi amplificano enormemente la produttività.

Personalmente in molte applicazioni che usano XML apprezzo l'uso di XSLT per costruirlo/modificarlo (http://c2.com/cgi/wiki?XsltAsSoftLayer) rispetto all'uso delle API DOM/SAX in java.

Ciao

71104
10-06-2005, 23:59
Basta...mettiamoci un bel . e continuicamo a trattare l'argomento...che era interessante... si però sinceramente il linguaggio usato da Daniele mi sembrava *cristallino*... :confused: e ve lo dice uno che di uscite strane ne ha... :D

cmq vorrei dire la mia: per evitare i problemi che ha avuto fek, MFC aiuta tantissimo: è una favola! qualsiasi memory leak viene segnalato al debugger (OutputDebugString, wrappata in AfxTrace, macro TRACE e compagnia bella), e tanto per cominciare mi sembra già un'ottima cosa, perché io ritengo che un programma che ha una buona gestione della memoria e che non fa nessun leak (nessuno!) è semplicemente un programma robusto!

poi MFC mette anche a disposizione altri strumenti di debug: le macro ASSERT, VERIFY, e ASSERT_VALID sono assolutamente ottime!! in particolare ASSERT_VALID è un wrapper per la funzione virtuale AssertValid (se ben ricordo) che qualsiasi classe derivata da CObject dovrebbe avere: viene implementata dal programmatore che crea la classe derivata da CObject, e serve semplicemente ad asserire quando viene chiamata e trova qualcosa che non va. naturalmente tutto l'overhead dovuto a questi strumenti viene completamente eliminato in modalità Release! :)

ricordo di aver fatto un piccolo esperimento una volta: ho creato un'applicazione MFC SDI scema scema utilizzando l'appwizard del visual studio (semplicemente un'applicazione vuota scegliendo le impostazioni predefinite del wizard); risultato: se ben ricordo erano 2 mega in modalità Debug e 300 kappa in Release. :)

siccome i simboli per il debug non occupavano quasi nulla (dovrebbero essere poco più grossi dei sorgenti stessi: si tratta essenzialmente di mappare le istruzioni assembly con le righe di codice C++, più qualche altra cosa per il debug multithreaded), tutto l'overhead era per controlli di debug e asserzioni; a occhio mi pare che MFC sia qualcosa di cui ci si può fidare... :) quando programmo ad alto livello lo uso sempre.

MFC lo ritengo una delle poche cose che hanno contemporaneamente queste due caratteristiche:
- made in Redmond
- di ottima qualità
e questo imho perché sono opensource (Microsoft sarebbe bene che imparasse da questo: IE avrebbe meno problemi). fatto sta che i bug di MFC si contano sulle punte delle dita.

cionci
11-06-2005, 00:09
Però MFC come framework è anche molto limitato...molto di più di wxWidgets e QT...

Se ti piacciono le MFC usa le wxWidgets...secondo me ti ci troveresti bene :)

DanieleC88
11-06-2005, 09:56
Se ti piacciono le MFC usa le wxWidgets...secondo me ti ci troveresti bene :)
Infatti, io di solito uso C, non C++, ma avevo letto qualcosa scritta con Qt e wxWidgets e sembra molto chiara. Forse le proverò anche io, un giorno o l'altro. ;)

Rispondo anche a ri: be', come vedi, già in tre hanno detto che non mi sono espresso male, in italiano. Forse dovresti farlo tu un ripasso di italiano. E ora basta, argomento chiuso. Torniamo a parlare di bug.

A proposito di bug (rispondete solo se vi sembra che questo non sposti troppo l'argomento di discussione): quale debugger usate, voi? Io uso gdb, soprattutto attraverso tool grafici, visto che sono un po' negato. :D

fek
11-06-2005, 10:39
A proposito di bug (rispondete solo se vi sembra che questo non sposti troppo l'argomento di discussione): quale debugger usate, voi? Io uso gdb, soprattutto attraverso tool grafici, visto che sono un po' negato. :D

Il debugger non dovrebbe mai essere usato se non in casi estremi :p
Sto cercando di curare la mia sindrome da abuso del debugger.

RaouL_BennetH
11-06-2005, 13:43
Sto entrando nell'ottica che non e' strettamente necessario usare un solo linguaggio per tutto il progetto, ma lo strumento giusto al momento giusto. Poi serve la colla per unire i vari linguaggi.

Evviva!! scusate, ma questa cosa mi conforta anche se in me ha avuto un processo inconscio.

Starete facendo queste faccine adesso, ci scommetto :huh: :mbe: ma vi assicuro che non sono impazzito, almeno, non ancora :)

Mi spiego:

Quando mi son trovato "costretto" a risolvere un problemino nell'azienduccia di mio padre in merito al rilievo delle presenze, ho agito così:

La parte che deve leggere i codici delle schede attraverso il lettore di badge, l'ho scritta in C. Ora, i dati di ingresso e di uscita, li ho interpretati come dati elementari ed ho fatto in modo che vengano memorizzati su file di testo (data la semplicità del dato da acquisire: codice scheda(numerico) ora di ingresso e ora di uscita.

Fatto questo, avevo un altro passaggio da effettuare, ovvero quello del prelievo di questi file dalla macchinetta per portarli sul pc. Bene, anche qui mi è stato comodo usare il C per la semplicità delle informazioni da trattare.

Per quanto concerne invece l'utilizzo da parte dell'utente (mio padre) in C non sarei riuscito a fare assolutamente nulla, e gli ho fatto l'interfaccia utilizzando visual basic e trattando i dati che arrivano dai file di testo memorizzandoli su un database mysql in modo che:

L'utente (mio padre) ha semplicemente dei bottoni sui quali cliccare per sapere :

Il dipendente X a che ora è entrato nel cantiere, quando è uscito e la durata di questo "intervallo" viene memorizzata in un'apposita tabella.

Ed altre cosine ma che non credo siano interessanti da trattare....

Ero fino a poco fa giù di morale (ma fino ad un certo punto, dato che di programmazione mi occupo da pochissimo e sempre a livello amatoriale) perchè pensavo che un "vero" programmatore, non avrebbe mai preso in considerazione usare diversi tool per realizzare un'applicazione, e le parole di fek in un certo senso mi hanno confortato :)

fek
11-06-2005, 14:38
Ero fino a poco fa giù di morale (ma fino ad un certo punto, dato che di programmazione mi occupo da pochissimo e sempre a livello amatoriale) perchè pensavo che un "vero" programmatore, non avrebbe mai preso in considerazione usare diversi tool per realizzare un'applicazione, e le parole di fek in un certo senso mi hanno confortato :)

E poi vai ripetendo su tutti i forum che non sei bravo :D

71104
11-06-2005, 14:59
Il debugger non dovrebbe mai essere usato se non in casi estremi :p
Sto cercando di curare la mia sindrome da abuso del debugger. perché??? :confused:
il debugger si usa quando serve; se serve spesso lo si usa spesso :confused:

cmq indovinate che uso io... :cool:

fek
11-06-2005, 15:18
perché??? :confused:
il debugger si usa quando serve; se serve spesso lo si usa spesso :confused:

cmq indovinate che uso io... :cool:


... http://www.testdriven.com/modules/news/ ... e dici addio al Debugger :)

Test driven development (TDD) is emerging as one of the most successful developer productivity enhancing techniques to be recently discovered. The three-step: write test, write code, refactor – is a dance many of us are enjoying. This site is dedicated to promoting techniques, tools, and general good will in the test-driven community.

ri
11-06-2005, 20:41
à in tre hanno detto che non mi sono espresso male, in italiano. Forse dovresti farlo tu un ripasso di italiano. E ora basta, argomento chiuso. Torniamo a parlare di bug.

http://www.aqs2000.com/sito/testi/fumetti/cattivik.jpg

Al calare delle nuove tenebre, il nero signore dei mostri tornerà a colpire... Cattivik non perdona!

uaz! uaz!

RaouL_BennetH
11-06-2005, 21:44
E poi vai ripetendo su tutti i forum che non sei bravo :D

Non solo lo ripeto, ma lo confermo.

Ma devo spiegarmi bene:

Quando penso a come affrontare un determinato problema, sono convinto di avere in testa tutto chiaro, come debba funzionare la cosa e come debba essere risolto il problema.

Le cose che mi mancano, fondamentalmente sono:

1) Cultura informatica
2) Una qualsiasi forma di didattica o di studi effettuati in campo informatico
3) La mania di voler dare uno "sguardo" su qualsiasi cosa, senza poi avere la testardaggine di approfondire
4) se li elenco tutti consumo la memoria disponibile ai server del forum.
5) il peggiore di tutti: al momento non posso permettermi di abbandonare il mio lavoro, per quanto schifoso sia, per sognare di potermi iscrivere ad un'università o seguire qualche corso più specifico che non sia una spasmodica ricerca su google e i numerosi post di aiuto che faccio in questa sezione.

Poi, leggendo anche i post vostri, quando entrate nel merito di certe discussioni, mi sembra di leggere letteratura extraterrestre con la convinzione che nonriuscirò mai a comprendere determinate cose.

Cmq, al momento va bene così :)

RaouL.

DanieleC88
12-06-2005, 09:51
http://www.aqs2000.com/sito/testi/fumetti/cattivik.jpg

Al calare delle nuove tenebre, il nero signore dei mostri tornerà a colpire... Cattivik non perdona!

uaz! uaz!
Mi pare che fek te l'abbia già suggerito, comunque, te lo ripeto:
http://www.albisole.it/inser/images/dacciuntagliologo.jpg

VICIUS
12-06-2005, 10:26
... http://www.testdriven.com/modules/news/ ... e dici addio al Debugger :)
Quoto. Ho finito di leggere il libro di Beck qualche settimana fa ed ti apre veramente gli occhi :D

ciao ;)

71104
12-06-2005, 12:29
Quoto. Ho finito di leggere il libro di Beck qualche settimana fa ed ti apre veramente gli occhi :D

ciao ;) io sono da un'altra parte: quei metodi di lavoro funzionano relativamente, e a quale prezzo? noi all'uni abbiamo appena finito di lavorare al progetto del corso di Laboratorio di Programmazione, e abbiamo sempre fatto unit testing (penso che si chiami anche così): il progetto era diviso in 4 "moduli" e per ciascuno bisognava creare oltre al codice principale anche il codice dei test. per la cronaca il progetto era un filtro antispam.
vi do la mia opinione: non solo alla fine il tempo di scrittura del codice è esattamente raddoppiato, ma i test (almeno per quanto mi riguarda) sono risultati al 90% inutili e per il rimanente 10% erano cose che avrei scoperto facendo il debug. conclusione: lasciate perdere quelle cavolate, semplicemente abituatevi a non fare nessun errore fin dalla prima volta: basta che imparate dai vostri errori quando ne trovate. ;)
sono sicuro che queste frasi disgusteranno mjordan, ma non m'interessa: ve lo do come consiglio, fateci quello che volete :)

PS: e usate il debugger! ;) e soprattutto usatene uno buono :cool:

PPS: un esempio di come io ho imparato dai miei errori: come già detto le MFC al termine dell'esecuzione del programma comunicano al debugger un dump completo di tutta la memoria non deallocata (non solo oggetti, anche comuni blocchi dell'heap), grazie agli hook che il framework installa per gli operatori new e delete. osservare quei dump ha sviluppato in me un occhio particolare per i memory leak: tutte le volte che uscivano i risultati di un modulo scoprivo con piacere di essere stato uno di quelli che avevano commesso il minor numero di leak, e a volte quelli che avevo commesso non dipendevano neanche da me ma da alcune librerie che abbiamo dovuto usare :cool:
senza contare che naturalmente lo unit testing non permette di scoprire i leak... :cool:

VICIUS
12-06-2005, 13:21
io sono da un'altra parte: quei metodi di lavoro funzionano relativamente, e a quale prezzo? noi all'uni abbiamo appena finito di lavorare al progetto del corso di Laboratorio di Programmazione, e abbiamo sempre fatto unit testing (penso che si chiami anche così): il progetto era diviso in 4 "moduli" e per ciascuno bisognava creare oltre al codice principale anche il codice dei test. per la cronaca il progetto era un filtro antispam.
vi do la mia opinione: non solo alla fine il tempo di scrittura del codice è esattamente raddoppiato, ma i test (almeno per quanto mi riguarda) sono risultati al 90% inutili e per il rimanente 10% erano cose che avrei scoperto facendo il debug. conclusione: lasciate perdere quelle cavolate, semplicemente abituatevi a non fare nessun errore fin dalla prima volta: basta che imparate dai vostri errori quando ne trovate. ;)
sono sicuro che queste frasi disgusteranno mjordan, ma non m'interessa: ve lo do come consiglio, fateci quello che volete :)
Quindi tu prima hai scritto il codice. Poi ti sei fatto un po' di debug ed infine hai scritto i test ? Test Driven Development è proprio il contrario. Prima si scrivono i test, poi si scrive il codice. Da quello che ho visto provandolo un po' su del codice semplice il debugger finisce nel dimenticatoio. Di sicuro per progetti più complessi serve ancora ma non nella stessa misura.

Per quanto riguarda il numero di test sei in linea con quanto detto nel libro. Secondo Beck non ha senso testare tutte le combinazioni possibili ed immaginabili. Con un po' di esperienza si arriva a capire quali casi limite testare e a scartare tutti gli altri. Fa un esempio per una classe molto semplice che gestisce i Triangoli e spiega come ha usato solo 7/8 test per testarla a differenza di un programmatore specializzato nella scrittura di test che è arrivato a ben 65 test.

Ti assicuro che prima di leggere il libro ero scettico pure io sulla utilita di una coa come TDD ma quando sono arrivato in fondo al libro mi sono dovuto ricredere. Non vuole di certo essere la cura a tutti i mali e cancellare tutte le altre metodologie ma semplicemente una tecnica alternativa quando non ti trovi a tuo agio con quello che dovrai andare a scrivere.

PS: e usate il debugger! ;) e soprattutto usatene uno buono :cool:
:mano: Qui mi trovi d'accordo. Se si deve usare un debugger meglio usarne uno buono. Usare gdb da console mi ha fatto uscire di testa piu di una volta quando potevo risolvere tutto in 10 minuti usandone uno grafico.

PPS: un esempio di come io ho imparato dai miei errori: come già detto le MFC al termine dell'esecuzione del programma comunicano al debugger un dump completo di tutta la memoria non deallocata (non solo oggetti, anche comuni blocchi dell'heap), grazie agli hook che il framework installa per gli operatori new e delete. osservare quei dump ha sviluppato in me un occhio particolare per i memory leak: tutte le volte che uscivano i risultati di un modulo scoprivo con piacere di essere stato uno di quelli che avevano commesso il minor numero di leak, e a volte quelli che avevo commesso non dipendevano neanche da me ma da alcune librerie che abbiamo dovuto usare :cool:
senza contare che naturalmente lo unit testing non permette di scoprire i leak... :cool:
Se non ricordo male cppunit puo tranquillamente controlalre dove e quando allochi la memoria e dirti se non la liberi.

ciao ;)

fek
12-06-2005, 14:49
io sono da un'altra parte: quei metodi di lavoro funzionano relativamente, e a quale prezzo? noi all'uni abbiamo appena finito di lavorare al progetto del corso di Laboratorio di Programmazione, e abbiamo sempre fatto unit testing (penso che si chiami anche così): il progetto era diviso in 4 "moduli" e per ciascuno bisognava creare oltre al codice principale anche il codice dei test. per la cronaca il progetto era un filtro antispam.
vi do la mia opinione: non solo alla fine il tempo di scrittura del codice è esattamente raddoppiato, ma i test (almeno per quanto mi riguarda) sono risultati al 90% inutili e per il rimanente 10% erano cose che avrei scoperto facendo il debug. conclusione: lasciate perdere quelle cavolate, semplicemente abituatevi a non fare nessun errore fin dalla prima volta: basta che imparate dai vostri errori quando ne trovate. ;)
sono sicuro che queste frasi disgusteranno mjordan, ma non m'interessa: ve lo do come consiglio, fateci quello che volete :)

Mio giovane padawan, sei troppo irruento, "fear leads to anger, anger leads to bugs..." :D
Ho notato che a volte dai giudizi categorici di impulso, e questi possono essere troppo affrettati, come in questo caso. Dare giudizi affrettati significa non essere in grado di apprezzare tutti gli aspetti di uno strumento e non poter sapere quando questo strumento ti possa venire utile o meno. E meno strumenti hai, meno frecce al tuo arco hai a disposizione quando devi risolvereu un problema. Mi piacerebbe leggere una tua opinione a questo proposito, riguardo al mio post sul WINE.

Tornando al TDD.

Al contrario di quanto si pensa, Test Driven Development non e' una metodologia di sviluppo che ha come scopo il testing del software. Sembra strano detto cosi', ma e' un errore piuttosto comune. Lo scopo del TDD e' scrivere software che risolva un problema e farlo nel minor tempo possibile con il design piu' semplice possibile. I test poi sono un prodotto della metodologia che si rivelano utili di per se'.

Le basi del TDD sono due:
- scrivere i test prima di scrivere il codice
- eliminare tutte le duplicazioni nel codice facendo refactoring

Scrivendo i test prima di scrivere il codice, tu formalizzi un processo mentale che fai sempre quando scrivi il codice.

Mi spiego meglio: quando scrivi un metodo, nel tuo cervello hai uno stato di partenza ed uno stato di arrivo che devi raggiungere e scrivi il codice per raggiungere lo stato di arrivo a partire da quello di partenza. Poi, di solito, lanci il programma e vedi se data una serie di input, il programma si comporta come ti aspetti. Quando questo non avviene, lanci il debugger, controlli lo stato delle variabili, esegui passo passo, sempre controllando che il valore delle variabili sia quello che ti aspetti. Trovi il bug quando hai uno stato che non ti aspetti, e poi modifichi il codice per ottenere il risultato che ti aspetti.

Non stai facendo altro che testing manuale.

TDD si basa invece sul principio che e' meglio che il computer faccia una cosa ripetitiva (testare gli stati del programma e la correttezza dei metodi), piuttosto che farla noi manualmente, di modo da poter usare il nostro tempo in maniera piu' furba.

Allora, dicevo, TDD formalizza quello che gia' facciamo quando programmiamo; davanti alla necessita' di aggiungere una funzionalita' al programma, scriviamo del codice che descriva come la funzionalita' deve comportarsi, in pratica documentiamo l'interfaccia della funzionalita', dettiamo come deve essere esposta, in pratica stiamo facendo il design della funzionalita', poi dichiariamo in maniera inequivocabile ed univoca come la funzionalita' deve comportarsi. Una volta che conosciamo l'interfaccia ed abbiamo dichiarato come il programma deve comportarsi, possiamo scrivere il codice che verifica l'interfaccia e soddisfa i requisiti ed abbiamo un chiaro momento in cui sappiamo quando dobbiamo fermarci a scrivere codice: quando il test passa.

L'ultima affermazione sembra una banalita', ma e' la chiave del tutto: in questo modo si tende a scrivere il codice minimo possibile per risolvere il problema. Il risultato netto e' scrivere meno codice di quando si programma "normalmente".

Passato il test, teoricamente questo non serve piu', il suo scopo e' concluso, possiamo anche buttarlo, ma visto che e' li' perche' non tenerlo? Tenere il test ha due vantaggi: da un lato ti documenta la funzionalita' in maniera univoca, dall'altro (se eseguito spesso) ti dice immediatamente quando scrivendo il codice hai rotto la funzionalita' che avevi gia' scritto. Quante volte ti e' capitato di scrivere codice e accorgerti che quello che avevi scritto non funziona piu' e non sapere che cosa di preciso hai cambiato per introdurre il bug? Accade in continuazione. La differenza facendo TDD e' che hai una rete di sicurezza che ti dice immediatamente quando qualcosa non va, invece che accorgertene magari dopo ore e poi lanciare il debugger a caccia del problema. Gia' solo questo, in pratica, porta ad un enorme guadagno di tempo. Non parlo dal punto di vista teorico, ma da quello pratico: faccio TDD da mesi e mi accorgo della differenza di produttivita' rispetto a quando non lo faccio al lavoro (perche' siamo alla fine del progetto).

Un'altra considerazione: e' impossibile non fare nessun errore fin dalla prima volta. Si diventa buoni programmatori nel momento in cui si accetta questo come un fatto compiuto e si lavora di modo da minimizzare l'impatto degli errori, sapendo che non sara' mai possibile non commetterne.

Sarebbe possibile non commettere mai errori se si avessero i requisiti da soddisfare sempre espressi in maniera inequivocabile dal cliente (e questo sai che e' impossibile), se i requisiti non cambiassero mai (altrettanto impossibile) e se conoscessimo in maniera esaustiva la soluzione al problema (e questo ammazza tutto, e' impossibile). La soluzione di un problema diviene sempre piu' chiara man mano che si risolve il problema stesso, ed e' giusto che il codice si evolva e si semplifichi man mano che conosciamo meglio il problema e la soluzione, da qui il refactoring che porta all'ultimo motivo per il quale i test sono importanti: hai mai provato a fare refactoring senza una batteria di test a proteggerti le spalle? Non lo auguro al mio peggior nemico :)

fek
12-06-2005, 14:52
senza contare che naturalmente lo unit testing non permette di scoprire i leak... :cool:

Come dice Beck, la maggior parte delle volte che si dice che lo unit testing non permette di testare qualcosa e' perche' non si sa come testarlo :)

Se tu scrivi i test prima del codice, imponi al tuo codice di non avere resource leak scrivendo prima i test che controllano questa condizione, ad esempio che una determinata classe sia distrutta al termine di un'operazione.

ri
12-06-2005, 16:24
Mi pare che fek te l'abbia già suggerito, comunque, te lo ripeto:
http://www.albisole.it/inser/images/dacciuntagliologo.jpg

era appunto un modo per darci un taglio :|
leggere fra le righe? :|

cionci
12-06-2005, 16:48
fek: mi interessa molto questo argomento... Hai link, ma soprattutto esempi... Ho fatto un po' di teoria su questa cosa, ma solo accennata...

71104
12-06-2005, 17:16
Quindi tu prima hai scritto il codice. Poi ti sei fatto un po' di debug ed infine hai scritto i test ? Test Driven Development è proprio il contrario. Prima si scrivono i test, poi si scrive il codice. Da quello che ho visto provandolo un po' su del codice semplice il debugger finisce nel dimenticatoio. Di sicuro per progetti più complessi serve ancora ma non nella stessa misura. non ho scritto prima il codice e poi i test, li ho scritti contemporaneamente e indipendentemente, un po' l'uno e un po' l'altro; il debug l'ho fatto alla fine di ogni modulo, a volte perché falliva un test, a volte perché il programma aveva comportamenti strani, che i test però non evidenziavano!! voi direte che i test li ho architettati male: ma non me li sono mica inventati io, noi abbiamo ricevuto delle specifiche ben precise dal prof (infatti non abbiamo neanche usato uno di quei frameworks che avete nominato). fosse stato per me i test non li avrei nemmeno fatti, solo debug, e avrei risparmiato un sacco di tempo; dubito che senza test il programma avrebbe avuto degli errori in più rispetto a quelli che ha (o che spero che non abbia :p).


Per quanto riguarda il numero di test sei in linea con quanto detto nel libro. Secondo Beck non ha senso testare tutte le combinazioni possibili ed immaginabili. Con un po' di esperienza si arriva a capire quali casi limite testare e a scartare tutti gli altri. lol, va a finire che escludi il caso banale proprio quando lo toppi :D


:mano: Qui mi trovi d'accordo. Se si deve usare un debugger meglio usarne uno buono. Usare gdb da console mi ha fatto uscire di testa piu di una volta quando potevo risolvere tutto in 10 minuti usandone uno grafico. aldilà della qualità del gdb (che non conosco, ma penso sia buona) il problema è che un'interfaccia grafica ce la devi sempre avere: puoi usare il debugger migliore del mondo, ma se lo usi da console serve a poco se non a farti diventare pazzo... ;)


Se non ricordo male cppunit puo tranquillamente controlalre dove e quando allochi la memoria e dirti se non la liberi. eh, ma come ti ho già detto i test secondo le specifiche date dal prof non usavano nessun framework e non potevano tenere traccia della memoria allocata: il codice doveva essere C standard compilabile su qualsiasi piattaforma (c'erano studenti che usavano Windows e altri che usavano Linux), e credo che un modo per tracciare l'heap in C standard non esista (può essere che mi sbaglio, non sono sicuro).

comunque alla fine che ti devi dire? io senza unit testing mi trovo benissimo, i miei programmi funziano, e se non funziano l'errore lo trovo immediatamente con un po' di debug (ma addirittura a volte li trovo così, semplicemente rileggendo alla fine il codice che ho scritto): il debug lo faccio spesso ma poco (cioè ogni volta che lo faccio, il mio fido debugger mi aiuta a trovare l'errore in pochissimo tempo :)); in altre parole, in 7 anni (quasi 8 ormai) di esperienza problemi come quelli che ha avuto fek mi sono capitati una volta sola, perché poi ho imparato. :)
basta solo che ci sviluppi l'occhio per gli errori: non solo ne commetterai di meno, ma ti abituerai anche a trovarli più facilmente analizzando il sorgente (debug + veloce). parlo solo per esperienza!! :)

fek
12-06-2005, 17:36
fek: mi interessa molto questo argomento... Hai link, ma soprattutto esempi... Ho fatto un po' di teoria su questa cosa, ma solo accennata...

Guarda, quando ho iniziato ho avuto anch'io la tua stessa difficolta' a trovare esempi; entrare nella mentalita' e' complicato, non riuscivo a capire ne' il ritmo ne' in che modo dovessi scrivere questi test. In rete non si trova molto.

Poi ho letto tre libri e da li' ho preso il via per iniziare a provare per conto mio:
- Test Driven Development di Kent Beck
- Refactoring to Patterns
- Extreme Programming Adventures in C# (http://www.amazon.co.uk/exec/obidos/ASIN/0735619492/qid=1118590486/sr=1-1/ref=sr_1_2_1/202-9864265-3263820[/url) di Ron Jeffries

L'ultimo e' un must scritto da un assoluto guru. Il libro non e' altro che lui mentre programma, i ragionamenti che fa, gli errori che commette e le spiegazioni del perche' commette quegli errori e come avrebbe potuto evitarli. E' anche un'applicazione di TDD ovviamente.

fek
12-06-2005, 17:49
non ho scritto prima il codice e poi i test, li ho scritti contemporaneamente e indipendentemente, un po' l'uno e un po' l'altro;

E' questo l'errore, i test vanno scritti prima ed il codice deve dipendere dai test, non devono essere indipendenti altrimenti si perde l'utilita' del definire l'interfaccia e il comportamento e poi derivarne il codice che lo implementa.

fosse stato per me i test non li avrei nemmeno fatti, solo debug, e avrei risparmiato un sacco di tempo; dubito che senza test il programma avrebbe avuto degli errori in più rispetto a quelli che ha (o che spero che non abbia :p).

Ovviamente qualunque programma ha difetti sempre e comunque :)

Lo scrivere i test non ti assicura che i difetti non esistano, ma questo non e' un buon motivo per non scriverli: avere anche solo un test e' meglio che non averne, in qualunque condizione. Questa e' un'ovvieta'.
E sono sicuro che se avessi applicato TDD in maniera precisa ed il piu' possibile rigorosa (cosa che non sono ancora capace a fare perche' richiede pratica), avresti impiegato meno tempo che scrivendo e debuggando. Ho 15 anni di esperienza, e piu' di 5 ormai come professionista, ne ho viste molte, e fino ad oggi non ho trovato una pratica che mi consenta di essere produttivo come il TDD.

Perche' scrivere test non e' una perdita di tempo come pensi, quando programmi devi sempre usare del tempo per definire il design di quello che stai scrivendo, non e' un tempo che puoi evitare. Il discorso e' come impiegare questo tempo in maniera effettiva, e per esperienza ti dico che fare il design del codice scrivendo test e' un ottimo modo di impiegare quel tempo, perche' oltre ad uscirne spesso un buon design, semplice, ha come prodotto collaterale test che verificano automaticamente una parte della correttezza del programma (che e' sempre e comunque meglio che non verificarla).



eh, ma come ti ho già detto i test secondo le specifiche date dal prof non usavano nessun framework e non potevano tenere traccia della memoria allocata: il codice doveva essere C standard compilabile su qualsiasi piattaforma (c'erano studenti che usavano Windows e altri che usavano Linux), e credo che un modo per tracciare l'heap in C standard non esista (può essere che mi sbaglio, non sono sicuro).

Non posso conoscere esattamente che cosa richiedesse il professore, ma e' possibile fare TDD senza usare alcun framework, in C puro, scrivendosi il framework mentre si scrivono i test.
"You don't need a testing framework, you need tests and lots of them"


comunque alla fine che ti devi dire? io senza unit testing mi trovo benissimo, i miei programmi funziano, e se non funziano l'errore lo trovo immediatamente con un po' di debug (ma addirittura a volte li trovo così, semplicemente rileggendo alla fine il codice che ho scritto): il debug lo faccio spesso ma poco (cioè ogni volta che lo faccio, il mio fido debugger mi aiuta a trovare l'errore in pochissimo tempo :)); in altre parole, in 7 anni (quasi 8 ormai) di esperienza problemi come quelli che ha avuto fek mi sono capitati una volta sola, perché poi ho imparato. :)

Ti dico con affetto che hai fatto un po' di affermazioni un po' presuntuose e che non puoi verificare ;)
Primo perche' non hai mai fatto Test Driven Development (almeno stando a cio' che hai scritto) quindi non puoi dire se ti trovi meglio con o senza, secondo perche' lavorare su un filtro anti spam non e' come lavorare su progetti di milioni di righe di codice con altri 30 programmatori, quindi non puoi dire di aver imparato tutto quello che c'e' da sapere su come evitare i bug.


basta solo che ci sviluppi l'occhio per gli errori: non solo ne commetterai di meno, ma ti abituerai anche a trovarli più facilmente analizzando il sorgente (debug + veloce). parlo solo per esperienza!! :)

Ed e' un'esperienza limitata, se mi permetti, perche' non tiene conto di moltissimi fattori, fra i quali il semplice fattore che ho gia' spiegato: non puoi scrivere codice senza scrivere bug. Si diventa un buon programmatore, come ho detto, quando si impara questa verita' e quando si impara che il design migliore e' un design semplice. Ed il modo piu' veloce che conosco per avere un design semplice e' fare TDD.

^TiGeRShArK^
12-06-2005, 18:16
ok ora mi metto a impararmi il TDD! :O

cionci
12-06-2005, 18:25
fek: ma un esempio tuo ? Anche a parole... Ritorniamo al problema precedente dei memory leak... Come si fa usando la TDD a testare i memory leak...

fek
12-06-2005, 18:59
fek: ma un esempio tuo ? Anche a parole... Ritorniamo al problema precedente dei memory leak... Come si fa usando la TDD a testare i memory leak...

Vero, hai ragione, proviamo a fare un esempio veloce. (Non fate caso se ci sono errori perche' non provo a compilare :D)

Problema: "Scrivere un classe che creare un oggetto Direct3D, assicurarsi che l'oggetto sia distrutto quando la classe e' distrutta per evitare un resource leak".

Per prima cosa scrivo il test, che esprime il requisito in maniera formale, immaginiamo che esista gia' il testing framework e che ci sia un sistema che esegue questo test automaticamente.


void TestDirect3DCreated()
{
// vogliamo un'istanza della classe Engine3D
Engine3D* engine = new Engine3D();

// asseriamo che dopo aver creato l'oggetto engine, questo e' stato
// creato correttamente
Assert(engine->IsCreated(), "Engine3d couldn't be created");
}


Compila questo codice e.... non compila :)
Test fallito. Ovvio, la classe Engine3D non esiste, dobbiamo ancora scriverla, pero' com questo test abbiamo gia' dichiarato due cose:

1) Vogliamo che il costruttore della classe non accetta parametri
2) Vogliamo che sia possibile chiedere all'oggetto se e' stato creato correttamente

Rispetto al non aver scritto nulla, sappiamo gia' almeno due cose in piu' e soprattutto abbiamo un obbiettivo chiaro e sappiamo esattamente quando abbiamo finito: quando questo test compila e passa.

Facciamolo compilare. Nel prossimo post.

fek
12-06-2005, 19:05
class Engine3D
{
Engine3D(void);

bool IsCreated(void) const;
};

Engine3D::Engine3D()
{
}

bool Engine3D::IsCreated() const
{
// ritorniamo il valore piu' banale per far compilare il metodo senza
// sapere per che cosa ci possa servire di preciso
return false;
}

void TestDirect3DCreated()
{
// vogliamo un'istanza della classe Engine3D
Engine3D* engine = new Engine3D();

// asseriamo che dopo aver creato l'oggetto engine, questo e' stato
// creato correttamente
Assert(engine->IsCreated(), "Engine3d couldn't be created");
}

Ho semplicemente scritto il codice piu' velocemente possibile di modo che il test compili, seguo il processo TDD alla lettera: fare passi minuscoli, scrivere il minimo indispensabile ad ogni passo.
Lancio il test. Compila. Test fallito! Bene!
Ora nel momento in cui riesco a far passare il test scrivendo del codice, so che il codice che ho scritto e' effettivamente cio' che ha provocato il passaggio dalla situazione con il test fallito alla situazione il test passato, ovvero la fine del mio compito.

Seguo TDD alla lettera, scrivo il codice minimo indispensabile per far passare il test, commettendo qualunque peccato debba commettere per farlo, tanto poi faccio refactoring e aggiusto il codice eliminando ogni duplicazione e ogni peccato. Ora voglio vedere solo il test passare.

Ecco il codice che devo cambiare:

bool Engine3D::IsCreated() const
{
return true;
}


Test passato! :D

fek
12-06-2005, 19:21
Ovvio che il test passa, ritorno sempre true :D

MA se guardi i test che abbiamo, l'unica cosa che il test richiede e' che creato un oggetto Engine3d, questo ritorni di essere stato creato correttamente. Il test non chiede altro. E' questo il cuore del TDD: implementare sempre e solo cio' che i test richiedono e niente di piu'. E non fare alcuna speculazione sul futuro, pur di mantenere il presente semplice.

Ci servono altri test che descrivano il resto del comportamento che impone il requisito.
Ecco un altro test:


void TestDestroyEngine()
{
Engine3D* engine = new Engine3D();

engine->Destroy();
Assert(!engine->IsCreated(), "Engine is still created");
}


Lanciamo. Non compila. Manca il metodo Destroy(). Va implementato.


class Engine3D
{
Engine3D(void);

void Destroy(void);
bool IsCreated(void) const;
};

Engine3D::Engine3D()
{
}

void Engine3D::Destroy(void) const
{
}

bool Engine3D::IsCreated(void) const
{
return true;
}



I test compilano entrambi. Lanciamo. Il primo test passa (quindi non lo abbiamo rotto col codice nuovo). Il secondo test fallisce. Bene!
Ora sappiamo che l'implementazione semplice di IsCreated non basta piu', bisogna aggiungere del codice per rispettare la nuova condizione imposta dal secondo test.

Ecco la nuova versione delle classe:


class Engine3D
{
Engine3D(void);

void Destroy(void);
bool IsCreated(void) const;

private:
bool mCreated;
};

Engine3D::Engine3D()
{
mCreated = true;
}

void Engine3D::Destroy(void) const
{
mCreated = false;
}

bool Engine3D::IsCreated(void) const
{
return mCreated;
}


Entrambi i test passati! Abbiamo finito? No.
C'e' una duplicazione in quello che abbiamo scritto e la duplicazione e' nascosta. Consiste nel valore true che abbiamo imposto nel test di creazione e nel valore true che abbiamo assegnato a mCreated all'interno del costruttore. La duplicazione di informazioni e' un male, quel true all'interno del costruttore dovrebbe essere "calcolato" in qualche modo per eliminare la duplicazione.
Come? Per esempio creato l'oggetto Direct3D, controllando che la creazione sia andata a buon fine, e poi assegnando il valore di questo test a mCreated.
Refactoring! E soprattutto: abbiamo due test che ci dicono se abbiamo fatto casino durante questo refactoring. Finche' i test passano, noi siamo tranquilli e finche' facciamo cambiamenti che coinvolgono solo piccoli passi, non abbiamo bisogno del debugger. Questo perche' ad ogni piccolo cambiamento, lanciamo i test, se i test falliscono, sappiamo che il problema e' nell'ultimo pezzettino (piccolo) di codice che abbiamo scritto. Non c'e' bisogno di perdere tempo dietro al debugger per saperlo. Ce lo dicono i test!

All'attacco. Nel prossimo post.

fek
12-06-2005, 19:33
class Engine3D
{
Engine3D(void);

void Destroy(void);
bool IsCreated(void) const;

private:
bool mCreated;

IDirect3D9* mD3D;
};

Engine3D::Engine3D()
{
// l'help delle D3D dice che questa funzione torna NULL se la creazion:
// e' fallita
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/functions/direct3dcreate9.asp
// notate che questo commento non serve, perche' il codice afferma lo gia'
// esplicitamente, questa e' duplicazione di informazioni!

mD3D = CreateDirect3D9(D3D_SDK_VERSION);
mCreated = mD3D != NULL;
}

void Engine3D::Destroy(void) const
{
if (mD3D != NULL)
{
mD3D->Release();
mD3D = 0;
}

mCreated = mD3D != NULL;;
}

bool Engine3D::IsCreated(void) const
{
return mCreated;
}


Refactoring finito. Sono bastate pochissime righe di codice. Lanciamo e... test passati! Abbiamo finito? No, ci vorrebbe un customer test, ma fare customer test su un forum e' davvero chiedere troppo :D
I test che abbiamo pero' ci dicono che quando creiamo un oggetto Engine3D e lo distruggiamo, l'oggetto Direct3D al suo interno viene sempre distrutto, nessun memory leak.

Domanda per voi: c'e' una duplicazione nell'ultima versione del codice. Chi la trova? Scrivete una versione senza duplicazione.

Seconda domanda: ci sono dei memory leak alla fine dei test. Volendo si possono anche sopportare, a noi interessa che l'applicazione non abbia memory leak, non i test. Se volessimo correggerli?

Infine, ovviamente avrei potuto scrivere tutta la classe al primo colpo in meno tempo, ma cosi non avrei avuto due test che mi diranno sempre automaticamente se la classe funziona come previsto. Inoltre avrei comunque speso del tempo per pensare al design della classe, ai parametri del costruttore, ai due metodi da creare, e avrei fatto questo design senza avere la classe sott'occhio e senza guardare a due esempi reali di uso della classe stessa, che aiutano a definire il design. Avrei comunque speso quel tempo, ma non avrei avuto i due test in cambio come premio per il tempo speso :)

cionci
12-06-2005, 19:59
Mi spieghi emglio cosa intendi per duplicazioni e refactoring ?

Per il memory leak nel test si definisce il distruttore per la classe di test e si sua la delete sul puntatore al motore 3d...

Altra domanda, ma tu sviluppi sempre così ? Il test si ferma a livello di modulo del programma o va anche oltre, ovviamente ogni modulo ha il suo test, ma verranno poi messi insieme in qualche modo ?

theClimber
12-06-2005, 20:44
Per approfondire ulteriormente argomento del TDD (ed anche XP) io consiglio anche il libro:
Agile Software Development: Principles, Patterns, and Practices
By Robert C. Martin (2002) (http://www.amazon.com/exec/obidos/tg/detail/-/0135974445/ref=ase_objectmentorinc/002-3900642-3957610?v=glance&s=books)

Sul sito dell'autore viene riportato un articolo (http://www.objectmentor.com/resources/articles/xpepisode.htm) tratto da uno dei capitoli, che e' una specie di "scena teatrale" di programmatori in azione; e' un po didattica e semplificata, ma abbastanza interessante. Approfondisce in particolare gli argomendi del TDD, della semplicita' del design e del pair programming.

x cionci: non ci sono solamente i test unitari. In molte metodologie agili si utilizzano test di acceptance di piu' alto livello per controllare il funzionamento e le features del programma nella sua interezza (Quelli che fek ha chiamato customer test qualche post prima). Nei casi ideali questi test sono anche delle milestone di sviluppo e delivery verso il cliente (Dimostrano che una feature del programma c'e' e funziona, con i dati richiesti dal cliente). Ci sono framework anche per gestire questi test (un po meno noti di junit), prova a dare un occhio a http://www.fitnesse.org/

71104
12-06-2005, 20:53
Mio giovane padawan, sei troppo irruento, "fear leads to anger, anger leads to bugs..." :D ma io non ho mica paura :confused:
e poi non è vero che la paura porta alla rabbia: la paura è una cosa, la rabbia è un'altra; hai mai visto un uomo terrorizzato arrabbiarsi?!? :D matto schizzato uno così :D cambiamenti d'umore insensati e immotivati :D
cmq sul fatto che la rabbia porti agli errori sono d'accordo :p
quando sono nervoso non scrivo codice, quando sono nervoso spengo proprio il PC e faccio sport (lo sport è uno sfogo, il migliore).
ma "padawan" che vuol dire? :mbe: suona come il nome di una razza di pellerossa... :p


Ho notato che a volte dai giudizi categorici di impulso, e questi possono essere troppo affrettati, come in questo caso. ma guarda che questo giudizio non era affrettato: l'ho maturato con l'esperienza! ti sarà sembrato affrettato solo perché è la prima volta che lo scrivo qui


Dare giudizi affrettati significa non essere in grado di apprezzare tutti gli aspetti di uno strumento e non poter sapere quando questo strumento ti possa venire utile o meno. E meno strumenti hai, meno frecce al tuo arco hai a disposizione quando devi risolvereu un problema. Mi piacerebbe leggere una tua opinione a questo proposito, riguardo al mio post sul WINE. una risposta riguardo ai giudizi affrettati o riguardo a WINE? :p


Tornando al TDD.

Al contrario di quanto si pensa, Test Driven Development non e' una metodologia di sviluppo che ha come scopo il testing del software. Sembra strano detto cosi', ma e' un errore piuttosto comune. Lo scopo del TDD e' scrivere software che risolva un problema e farlo nel minor tempo possibile con il design piu' semplice possibile. I test poi sono un prodotto della metodologia che si rivelano utili di per se'. capisco.
però la mia esperienza dimostra che ci sono metodi più veloci: come la mettiamo?
se anziché scrivere prima i test, poi il codice errato, e infine il codice corretto, scrivi direttamente il codice corretto, non è meglio? ti sei risparmiato la scrittura dei test e del codice errato
credi che scrivere direttamente il codice corretto sia difficile o impossibile? ecco, questo è quello che io chiamo un giudizio affrettato ;)


Mi spiego meglio: quando scrivi un metodo, nel tuo cervello hai uno stato di partenza ed uno stato di arrivo che devi raggiungere e scrivi il codice per raggiungere lo stato di arrivo a partire da quello di partenza. Poi, di solito, lanci il programma e vedi se data una serie di input, il programma si comporta come ti aspetti. Quando questo non avviene, lanci il debugger, controlli lo stato delle variabili, esegui passo passo, sempre controllando che il valore delle variabili sia quello che ti aspetti. Trovi il bug quando hai uno stato che non ti aspetti, e poi modifichi il codice per ottenere il risultato che ti aspetti. perfetto. e aggiungo anche che alla fine devi imprimere A FUOCO nel tuo cervello questa tua esperienza: figurati una maniera per accorgerti immediatamente in futuro di errori analoghi, sviluppaci l'occhio per quella cosa! quando avevo 13 anni e programmavo in Delphi certe volte credevo che il compilatore Delphi fosse bacato perché ogni tanto i programmi avevano comportamenti inspiegabili completamente separati da quello che succedeva (o che sembrava succedere) dall'interno del debugger: variabili che prima avevano un valore e all'istruzione successiva ne avevano un altro senza che fosse stata eseguita nessuna istruzione su di esse! watch che andavano per conto loro! quando divenni più grandicello iniziai ad analizzare gli assemblati generati dal compilatore e vidi che erano perfetti; dal momento che in Object Pascal mi andava sempre male imparai il C++: grazie al C++ capii molte cose senza le quali era possibile lavorare in Pascal, ma impossibile in C++; ad esempio capii che le classi erano solitamente gestite tramite puntatori, che la loro gestione tramite puntatori in Object Pascal era del tutto implicita (e per forza che io non la vedevo), e che l'heap era quella regione la cui dimensione poteva crescere dinamicamente nella quale i programmi allocano dati di dimensioni ignote. tutte banalità che non potevo certo sapere avendo solo letto il manuale di Delphi. dopo aver capito tutte queste cose, le mie sessioni di debug erano più consapevoli, e gli errori sempre meno frequenti (vi ho commossi? :sofico: )


Non stai facendo altro che testing manuale. che va benissimo, purché tu ne faccia sempre di meno col passare degli anni e con l'aumentare della tua esperienza; alla fine in un arco di tempo abbastanza lungo qualsiasi grandezza descrescente converge, no?


TDD si basa invece sul principio che e' meglio che il computer faccia una cosa ripetitiva (testare gli stati del programma e la correttezza dei metodi), piuttosto che farla noi manualmente, di modo da poter usare il nostro tempo in maniera piu' furba. si, ma sul fatto che questa maniera sia più furba ho qualcosa da ridire, visto che lo devi sprecare ad insegnare a quel tontolone del computer come si fanno i test :D


[...] L'ultima affermazione sembra una banalita', ma e' la chiave del tutto: in questo modo si tende a scrivere il codice minimo possibile per risolvere il problema. Il risultato netto e' scrivere meno codice di quando si programma "normalmente". l'ultima affermazione non mi è sembrata una banalità, mi è sembrata un paradosso :confused:: tu dici che quando scrivo codice normalmente, solo a causa delle correzioni che faccio impiego più tempo che non scrivendo i test?!? :confused:
forse non riesco a concepire questa cosa perché noi all'uni non abbiamo usato un framework per lo unit testing; magari i framework che ci sono ti semplificano la vita, poi non so...


Passato il test, teoricamente questo non serve piu', il suo scopo e' concluso, possiamo anche buttarlo, ma visto che e' li' perche' non tenerlo? Tenere il test ha due vantaggi: da un lato ti documenta la funzionalita' in maniera univoca, dall'altro (se eseguito spesso) ti dice immediatamente quando scrivendo il codice hai rotto la funzionalita' che avevi gia' scritto. Quante volte ti e' capitato di scrivere codice e accorgerti che quello che avevi scritto non funziona piu' e non sapere che cosa di preciso hai cambiato per introdurre il bug? Accade in continuazione. be' guarda, io sono del parere che gli errori di memoria sono una vera piaga, ma una volta che sei riuscito ad eliminare quelli tutti gli altri sono evidenti.
capita anche a me che saltino fuori gli errori "dal nulla", non così spesso come dici ma capita, ma si tratta sempre di cose evidenti che si trovano subito col debugger o addirittura senza! semplicemente riguardando il codice.


La differenza facendo TDD e' che hai una rete di sicurezza che ti dice immediatamente quando qualcosa non va, invece che accorgertene magari dopo ore e poi lanciare il debugger a caccia del problema. ma perché lanciarlo dopo ore scusa?? se ti accorgi di un cambiamento inatteso lancialo subito il debugger, no? a meno che non riesci a trovare l'errore ancora prima di lanciare il debugger, semplicemente leggendo il codice; perché guarda che alla fine se uno ha programmato per anni, gli errori che commette sono sempre banalità, te l'assicuro!! altrimenti tutta la sua esperienza dove starebbe? :)


Gia' solo questo, in pratica, porta ad un enorme guadagno di tempo. Non parlo dal punto di vista teorico, ma da quello pratico: faccio TDD da mesi e mi accorgo della differenza di produttivita' rispetto a quando non lo faccio al lavoro (perche' siamo alla fine del progetto). secondo me questo TDD ti vizia


Un'altra considerazione: e' impossibile non fare nessun errore fin dalla prima volta. Si diventa buoni programmatori nel momento in cui si accetta questo come un fatto compiuto e si lavora di modo da minimizzare l'impatto degli errori, sapendo che non sara' mai possibile non commetterne. in teoria è possibile; perché non dovrebbe esserlo in pratica? vedi che continui a dare "giudizi affrettati"? :) semplicemente fai in modo che lo sia. come devi fare per fare in modo che lo sia? una maniera ottima (sarà l'80^ volta che lo riscrivo T_T) è quella di imparare dai propri errori; inizialmente potrebbe non bastare, è normale, ma vedrai che piano piano inizierai a programmare "per stereotipi": se ciascuno stereotipo è completamente corretto di per se', alla fine tutto il programma sarà corretto.


Sarebbe possibile non commettere mai errori se si avessero i requisiti da soddisfare sempre espressi in maniera inequivocabile dal cliente (e questo sai che e' impossibile), se i requisiti non cambiassero mai (altrettanto impossibile) e se conoscessimo in maniera esaustiva la soluzione al problema (e questo ammazza tutto, e' impossibile). La soluzione di un problema diviene sempre piu' chiara man mano che si risolve il problema stesso, ed e' giusto che il codice si evolva e si semplifichi man mano che conosciamo meglio il problema e la soluzione, da qui il refactoring che porta all'ultimo motivo per il quale i test sono importanti: hai mai provato a fare refactoring senza una batteria di test a proteggerti le spalle? Non lo auguro al mio peggior nemico :) ehm, purtroppo non so cosa voglia dire "refactoring" :mc: :doh:
comunque secondo me scrivere codice corretto non dipende dai requisiti del cliente; il codice per essere corretto deve semplicemente soddisfare al 100% i requisiti richiesti aldilà del fatto che il cliente non abbia chiaro ciò che lui stesso vuole (normale visto che il poveretto non è un programmatore, altrimenti il programma se lo farebbe da se'); i requisiti possono anche cambiare, ma l'importante è che tu li soddisfi. se il cliente non è stato ben chiaro su qualche punto, potete sempre chiarire.

cionci
12-06-2005, 20:54
Tutto questo è interessantissimo...e mi sa che mi ci butto :)

fek
12-06-2005, 20:57
Mi spieghi emglio cosa intendi per duplicazioni e refactoring ?

Per duplicazione intendo ogni volta che "affermi" un concetto o produci un'informazione in due punti diversi.

Un esempio banale:


void SomeMethod()
{
if (x < 100)
// do something

if (x > 100)
// do something else

// do nothing
}


Il numero 100 e' ripetuto due volte, c'e' una duplicazione di informazioni. Puoi sostituirlo con una costante.

Oppure quando all'interno di uno stesso metodo ci sono dei blocchidi codice che fanno la stessa cosa: puoi estrarre il blocco di codice in un metodo e sostituire una chiamata. Hai eliminato la duplicazione.

La definizione di Refactoring e': "Una serie di modifiche alla struttura interna del codice che non ne modifica il comportamento osservabile".
Negli esempi precedenti quando sostituisci al numero una costante, oppure estrai un blocco di codice in un metodo e sostituisci una chiamata a quel metodo, stai migliorando la struttura interna del codice, ma non stai modificando il suo comportamento osservabile: le due versioni del codice fanno piu' o meno la stessa cosa.

Altra domanda, ma tu sviluppi sempre così ? Il test si ferma a livello di modulo del programma o va anche oltre, ovviamente ogni modulo ha il suo test, ma verranno poi messi insieme in qualche modo ?

Dipende, al lavoro non sempre, perche' siamo alla fine del progetto e perche' quando imparo qualcosa di nuovo cerco prima di provarlo per conto mio a lungo, per poi portarlo al lavoro se si rivela utile. Nei miei progetti paralleli si', sempre, soprattutto in C# e in Java che hanno tool appositi che aiutano a scrivere ed eseguire test. Sono ancora scarso pero' a scrivere Test Driven :) Sono troppo abituato ai metodi classici di sviluppo e tendo a fare passi troppo lunghi, invece dei passettini che ho descritto qui, e poi mi ritrovo impelagato nel debugger a capire dove ho sbagliato. Si diventa bravi a fare TDD quando si riesce a modificare la lunghezza dei passi in base al problema e si e' capaci di fare passetti piccoli e semplici quando e' necessario. Non e' per nulla facile.

I test possono essere scritti a qualunque livello di astrazione e prendono nomi diversi: quelli che ho mostrato qui si chiamano unit o programmer's test. Quando integri un modulo con un altro scrivi integration o functional test. Quando il cliente scrive un test per verificare che l'applicazione incontri i requisiti richiesti, scrive customer test. Poi ci sono test di regressione, stress test per mettere sotto stress l'applicazione (ad esempio aprire 1000 connessioni ad un database per vedere come si comporta, oppure eseguire un'applicazione di rete con una connessione con poca banda).

cionci
12-06-2005, 21:01
71104: io non so cosa tu abbia programmato nella tua vita...ma non credo che la tua esperienza sia paragonabile a quella di fek...e non credo che tu abbia lavorato in un team di sviluppo composto da molte persone... Queste metodologie sono applicate nei grandi team di sviluppo...e servono non solo per arrivare al completamente della parte di codice che devi fare, ma anche al coordinamento dei vari componenti... Quando farai ingegneria del software te ne renderai conto...

cionci
12-06-2005, 21:07
Quando il cliente scrive un test per verificare che l'applicazione incontri i requisiti richiesti, scrive customer test.
Questo ad esempio in cosa consiste... E' sempre possibile realizzarlo ? Ad esempio mi sembra banale per un server db, ma per un gioco come si fa ? Magari ci si ferma a testare l'engine ? Se i riquisiti richiedono caratteristiche relative all'interfaccia utente (dal punto di vista dell'usabilità) oppure altre caratteristiche oggettive (come ad esempio la longevità di un gioco) come è possibile verificarli con un customer test ?

71104
12-06-2005, 21:09
71104: io non so cosa tu abbia programmato nella tua vita...ma non credo che la tua esperienza sia paragonabile a quella di fek...e non credo che tu abbia lavorato in un team di sviluppo composto da molte persone... Queste metodologie sono applicate nei grandi team di sviluppo...e servono non solo per arrivare al completamente della parte di codice che devi fare, ma anche al coordinamento dei vari componenti... Quando farai ingegneria del software te ne renderai conto... ecco, ammetto che anche questo è vero: ho 7-8 anni di esperienza ma in grossi team non ci ho mai lavorato e Ingegneria del Software non l'ho ancora fatta :mc:
credo che questo risolva definitivamente la discussione tra me e fek :)
ho parlato in base alla mia esperienza "inusuale", completamente basata sull'autodidattica; penso di aver sempre studiato su ottimo materiale, ma il metodo non si studia da nessuna parte.
fek, non appena ho fatto Ingegneria del Software però ne riparliamo, eh? :D
in fondo chissà, può darsi che in un modo o nell'altro abbiamo ragione entrambi, e che come spesso accade esista il compromesso tra le due parti...

fek
12-06-2005, 21:13
ma guarda che questo giudizio non era affrettato: l'ho maturato con l'esperienza! ti sarà sembrato affrettato solo perché è la prima volta che lo scrivo qui

No, e' affrettato, perche' non puoi dare un giudizio su una pratica se non l'hai mai provata.


una risposta riguardo ai giudizi affrettati o riguardo a WINE? :p

WINE, mi interessa molto.


capisco.
però la mia esperienza dimostra che ci sono metodi più veloci: come la mettiamo?

La mettiamo che la tua esperienza non e' adeguata (non lo e' neppure la mia). Esistono svariati studi (Microsoft e IBM in prims) che hanno gia' dimostrato che e' piu' produttivo scrivere gli unit test; questo e' un fatto assodato nell'Ingegneria del Software, non e' sotto discussione. Code Complete 2 affronta questo argomento e riporta gli studi in dettaglio fornendone i dati.
Microsoft per ogni programmatore ha un altro programmatore che scrivere gli integration test e parte dei programmer's test: se non fosse una pratica produttiva e non gli costasse meno, non lo farebbero.


se anziché scrivere prima i test, poi il codice errato, e infine il codice corretto, scrivi direttamente il codice corretto, non è meglio? ti sei risparmiato la scrittura dei test e del codice errato
credi che scrivere direttamente il codice corretto sia difficile o impossibile? ecco, questo è quello che io chiamo un giudizio affrettato ;)

Non e' cosi' facile :)
Perche' spesso, anzi, la maggior parte delle volte, non conosci il codice corretto e la soluzione prima di aver iniziato a scriverla. Teoricamente sarebbe piu' veloce scrivere il codice corretto immediatamente, praticamente questo e' impossibile nella stragrande maggioranza dei casi, e anche quando fosse possibile, scrivere un test significa avere uno strumento che automaticamente riafferma la validita' della soluzione a fronte di cambiamenti nel codice (refactoring) o in altre parti di codice. Quando il test fallisce, l'ultimo cambiamento ha provocato un danno, senza aver bisogno del debugger o di un test manuale per saperlo e risparmiando molto tempo, visto che statisticamente la scrittura del codice e' meno del 20% del tempo impiegato a produrre un'applicazione. Il resto del tempo si spende in design, refactoring e debugging. Da queste statistiche deriva l'utilita' pratica e la maggior produttivita' dei test automatici che, ti ripeto, e' un fatto assodato da decenni di studi.


si, ma sul fatto che questa maniera sia più furba ho qualcosa da ridire, visto che lo devi sprecare ad insegnare a quel tontolone del computer come si fanno i test :D

Ma poi il tontolone e' in grado di ripetere quel test automaticamente migliaia di volte piu' velocemente di quanto possa farlo io, facendomi risparmiare tempo :)
Ti ripeto, questo non e' un giudizio, questo e' un fatto. Fare testing e' piu' produttivo, resta da discutere se sia meglio scrivere i test prima o dopo il codice, ma non si discute sul fatto che e' piu' produttivo scrivere i test che non scriverli. E' un fatto provato.


l'ultima affermazione non mi è sembrata una banalità, mi è sembrata un paradosso :confused:: tu dici che quando scrivo codice normalmente, solo a causa delle correzioni che faccio impiego più tempo che non scrivendo i test?!? :confused:[/quote

Si', impieghi piu' tempo a debuggare e a correggere il codice e poi a ricontrollare che la correzione sia giusta piuttosto che affidandoti a test automatici che minimazzano (non azzerano) quei due tempi.

[quote] ma perché lanciarlo dopo ore scusa?? se ti accorgi di un cambiamento inatteso lancialo subito il debugger, no? a meno che non riesci a trovare l'errore ancora prima di lanciare il debugger, semplicemente leggendo il codice; perché guarda che alla fine se uno ha programmato per anni, gli errori che commette sono sempre banalità, te l'assicuro!! altrimenti tutta la sua esperienza dove starebbe? :)

Se ti accorgi di un cambiamento, ma se non te ne accorgi e se ne accorge solo l'utente finale? :)
Ore e ore di debugging, quando un semplice test ripetuto ogni qualche minuto te lo avrebbe detto immediatamente.


in teoria è possibile; perché non dovrebbe esserlo in pratica? vedi che continui a dare "giudizi affrettati"? :) semplicemente fai in modo che lo sia. come devi fare per fare in modo che lo sia? una maniera ottima (sarà l'80^ volta che lo riscrivo T_T) è quella di imparare dai propri errori; inizialmente potrebbe non bastare, è normale, ma vedrai che piano piano inizierai a programmare "per stereotipi": se ciascuno stereotipo è completamente corretto di per se', alla fine tutto il programma sarà corretto.

In teoria e' impossibile scrivere codice esente da difetti. E lo e' anche in pratica. Guarda, ho commesso molti piu' errori di quanti tu ne puoi anche immaginare ;)
Ed e' giusto imparare dagli errori, ma anche avendo esperienza infinita, resta il problema che non puoi conoscere la soluzione al problema a priori fino a che non inizi a implementarla. Non puoi pensare di scrivere centinaia di righe di codice e pensare che funzionino senza errori. E' impossibile. Puoi scrivere un po', verificare che quel funziona, scrivere un altro po', verificare quell'altro po' funziona. La differenza e' che tu lo verifichi a mano, io lo faccio verificare al computer automaticamente in una frazione del tempo, per questo vado piu' spedito.


ehm, purtroppo non so cosa voglia dire "refactoring" :mc: :doh:

E no... e no... e no... e proprio no... :)
Se non sai che cosa sia il refactoring, allora non hai esperienza di alcun tipo :)
(Lo dico in senso buono, non ti offendere).
Il Refactoring e' l'ABC della programmazione assieme ai Design Pattern; e' lo strumento principe per scrivere software. Se non si sa fare refactoring, non si sa programmare.

fek
12-06-2005, 21:17
Questo ad esempio in cosa consiste... E' sempre possibile realizzarlo ? Ad esempio mi sembra banale per un server db, ma per un gioco come si fa ? Magari ci si ferma a testare l'engine ? Se i riquisiti richiedono caratteristiche relative all'interfaccia utente (dal punto di vista dell'usabilità) oppure altre caratteristiche oggettive (come ad esempio la longevità di un gioco) come è possibile verificarli con un customer test ?

E' possibile fare customer test in un gioco? Non ne ho idea, non ci ho mai provato :D
Sicuramente alcuni aspetti sono testabili automaticamente, e testare qualcosa e' meglio che non testare proprio, ma aspetti come la giocabilita' e la longevita' non lo sono.
Questi aspetti devono essere testati da reparti di QA, gente che gioca. Pero' vedi, piuttosto che usare un umano per testare manualmente aspetti che possono essere testati automaticamente ("se il soldato tira una freccia e colpisce un altro soldato questo muore"), puo' risparmiare tempo e concentrarsi su aspetti piu' interessanti ai fini della giocabilita' ("e' piu' divertente se il nemico muore con una o due frecce?").

fek
12-06-2005, 21:20
fek, non appena ho fatto Ingegneria del Software però ne riparliamo, eh? :D
in fondo chissà, può darsi che in un modo o nell'altro abbiamo ragione entrambi, e che come spesso accade esista il compromesso tra le due parti...

Ma certo che ne riparliamo :)

TDD e' uno strumento, quando ti dico di non dare giudizi affrettati sugli strumenti se non li hai provati, e' perche' il compromesso sta nel sapere non solo che cosa sia uno strumento, ma quando usarlo e soprattutto quando non usarlo.

Se impari a fare TDD e Refactoring, saprai che la sera prima di una milestone non puoi fare ne' TDD ne' Refactoring perche' devi velocemente consegnare il prodotto e non puoi perdere tempo a rendere la soluzione robusta. E saprai che consegnata la milestone, dovrai tornare a scrivere i test e "pagare i debiti" che hai accumulato la sera prima.

Programmare e l'esperienza non sono non commettere mai errori, ma sapere quali e quando usare gli strumenti a propria dispozione: piu' strumenti hai, meglio programmi e meno difetti conterra' il codice che consegni.

Edit: guarda, quando io avevo 7/8 anni di esperienza, ma anche 10, non sapevo programmare :D Ma neppure un pochetto. Ho imparato a programmare decentemente, neanche tanto bene, negli ultimi due anni.

cionci
12-06-2005, 21:23
Ad ingegneria del software ho preso 30...ma la parola refactoring proprio non me la ricordavo... Però sui design pattern ci chiappo :) Ed ora per passare al nuovo ordinamento devo anche fare un estensione dell'esame... Devo studiare CORBA...

Una domanda stupida... L'hai mai usato il singleton ? Molte delle persone con cui ho parlato mi hanno detto che secondo loro è inutile e che anzi è una pratica dannosa programmando OO...
In effetti pensandoci bene corrisponde alla vecchia variabile globale del C :)

theClimber
12-06-2005, 21:24
comunque secondo me scrivere codice corretto non dipende dai requisiti del cliente; il codice per essere corretto deve semplicemente soddisfare al 100% i requisiti richiesti aldilà del fatto che il cliente non abbia chiaro ciò che lui stesso vuole (normale visto che il poveretto non è un programmatore, altrimenti il programma se lo farebbe da se'); i requisiti possono anche cambiare, ma l'importante è che tu li soddisfi. se il cliente non è stato ben chiaro su qualche punto, potete sempre chiarire.

E' proprio qui che il TDD serve maggiormente: spesso i requisiti sono incompleti o incomprensibile da chiarire, e le informazioni arrivano a membri diversi del team di sviluppo.

I test servono chiarirsi le idee su cosa si vuole da certe classi/metodi, in per scrivere le API piu' chiare e comprensibili possibili, e per mantenerle manutenibili. Inoltre diventano degli esempi di utilizzo del sistema, utili per far entrare nel gruppo di lavoro nuove persone nel piu' breve tempo possibile.

Spesso in un progetto software non usa e getta il tempo speso a moficare, rileggere, ripianificare il codice e' molto maggiore della scrittura iniziale. Il tempo speso in debug, che sistema si il problema, ma non documenta la soluzione, non fornisce assistenza in tutte le fasi successive.

NOTA: in questo sto un po esulando da problemi di gestione memoria, che generalmente sono a un livello troppo basso per gli interessi del cliente stesso. Per ridurre questi errori il metodo migliore mi sembrerebbe quello di usare un linguaggio differente ( Java? C# ? Pyhton? Smalltalk? OCaml ? ) ;)

fek
12-06-2005, 21:32
Ad ingegneria del software ho preso 30...ma la parola refactoring proprio non me la ricordavo... Però sui design pattern ci chiappo :) Ed ora per passare al nuovo ordinamento devo anche fare un estensione dell'esame... Devo studiare CORBA...

Refactoring di Martin Fowler e Refactoring to Patterns di non mi ricordo mai il nome devono essere tuoi :)


Una domanda stupida... L'hai mai usato il singleton ? Molte delle persone con cui ho parlato mi hanno detto che secondo loro è inutile e che anzi è una pratica dannosa programmando OO...
In effetti pensandoci bene corrisponde alla vecchia variabile globale del C :)

Sto cercando di guarire da un'acuta forma di Singletonitis, che mi ha portato negl'anni ad abusare di Singleton. Ora non li posso vedere, ho il rigetto :(

theClimber
12-06-2005, 21:33
Una domanda stupida... L'hai mai usato il singleton ? Molte delle persone con cui ho parlato mi hanno detto che secondo loro è inutile e che anzi è una pratica dannosa programmando OO...
In effetti pensandoci bene corrisponde alla vecchia variabile globale del C :)

Essenzialmente si, ma forse e' anche peggio, dato che le variabili globali non esistono veramente, dipende solo dal contesto che consideri come globale.

Il problema di base a mio parere e' che e' un pattern che sembra semplice (E' sostanziamlmente il pattern piu' comprensibile tra quelli presentati nel libro "Design Patterns" della Gang of 4), quindi viene sparso in giro a man bassa, e poi sono problemi.

I problemi tipici che ho dovuto disinnescare sul singleton:
- Singleton Onniscente che carica 1200 classi di dipendenza. Per creare una pagina web semistatica che ne usava una properti ho dovuto mettere nel classpath 30Mb di jar :mad:
- Architetture distribuite server side basate solo su singleton. Esempio java:
1 Faccio un bel singleton :)
2 Si, ma poi la classe dipende dal classloader... :confused: (La stessa classe caricata da 2 classloader --> 2 istanze del singleton... E' un dualton ? )
3 Si ma poi se voglio clusterizzare l'applicazione, ho piu' JVM... :muro:

Ciao

^TiGeRShArK^
12-06-2005, 21:33
if (mCreated)

Domanda per voi: c'e' una duplicazione nell'ultima versione del codice. Chi la trova? Scrivete una versione senza duplicazione.

il codice ke ho scritto anzikè if (mD3D != NULL) nel destroy.
Giusto?

fek
12-06-2005, 21:35
il codice ke ho scritto anzikè if (mD3D != NULL) nel destroy.
Giusto?

No! Dai che' facile, guarda mCreated, ti serve davvero?

^TiGeRShArK^
12-06-2005, 21:38
boh...
devo scappare ke vado a giocare a D&D...
qdo torno gli do un okkiata decente :P

cionci
12-06-2005, 21:38
Non serve a niente :) Basta ritornare mD3D != NULL in IsCreated...

fek
12-06-2005, 21:39
Non serve a niente :) Basta ritornare mD3D != NULL in IsCreated...

Bingo!
Questo e' un Refactoring :)

VICIUS
12-06-2005, 21:52
Ma quel test finale non è sempre vero ? a questo punto tanto vale sostituirlo con return false;. giusto ?

ciao ;)

fek
12-06-2005, 22:02
Ma quel test finale non è sempre vero ? a questo punto tanto vale sostituirlo con return false;. giusto ?

ciao ;)

Quale test? Ho sbagliato qualche cosa?

Beh, tutti i test devono essere sempre veri quando va tutto bene :)

VICIUS
12-06-2005, 22:24
Quale test? Ho sbagliato qualche cosa?

Beh, tutti i test devono essere sempre veri quando va tutto bene :)
Ignorami. Troppa pizza e una birretta di troppo :p

Quello che volevo scrivere era che nella funzione Destroy alla fine quando assegni mCreated il test ritorna sempre lo stesso valore, "false". Quindi si puo assegnare una costante.
void Engine3D::Destroy(void) const
{
if (mD3D != NULL)
{
mD3D->Release();
mD3D = 0;
}

mCreated = false;
}

fek
12-06-2005, 22:38
Quello che volevo scrivere era che nella funzione Destroy alla fine quando assegni mCreated il test ritorna sempre lo stesso valore, "false". Quindi si puo assegnare una costante.

Si' e' vero, ma cosi' introduci una duplicazione fra il valore che ritorni e quello che testi.
In realta' va bene anche la tua versione, perche' con la mia versione faccio questo ragionamento: se in futuro introduco il codice fra la distruzione dell'oggetto e il ritorno della funzione, magari mi sbaglio e non distruggo piu' l'oggetto e se ritorno un valore costante il test non fallisce e non me lo segnala.
L'argomento contrario e' che sto scrivendo piu' codice in previsione di qualcosa che magari potro' scrivere in futuro, e questo non andrebbe mai fatto.

Alla fine, e' questione di esperienza e dipende dalla propria sensibilita' credo. Qui preferisco non ritornare una costante, ma ritornare una costante non e' affatto sbagliato.

Tanto poi mCreated alla fine si elimina e vissero tutti felici e contenti :D

71104
13-06-2005, 02:27
No, e' affrettato, perche' non puoi dare un giudizio su una pratica se non l'hai mai provata. hai ragione, ho detto male: non mi riferivo al giudizio che do alla pratica del TDD, ma a come giudico il mio metodo :p cioè non fare TDD; ma siccome il mio metodo lo giudico buono e credo di dover utilizzare quello, l'altro lo considero da scartare ^^


WINE, mi interessa molto. ok, ho risposto (spero di aver capito bene a quale post volevi che rispondessi ^^)


La mettiamo che la tua esperienza non e' adeguata (non lo e' neppure la mia). Esistono svariati studi (Microsoft e IBM in prims) che hanno gia' dimostrato che e' piu' produttivo scrivere gli unit test; questo e' un fatto assodato nell'Ingegneria del Software, non e' sotto discussione. s questo forum a quanto pare ci sono persone che vanno controcorrente, che non credono a quello che dice la gente, credono solo alla loro esperienza, perché la loro esperienza è quello che hanno visto coi loro occhi e sperimentato sulla loro pelle. una di queste è (se ben ricordo, non vorrei dire scemenze ^^) VICIUS, che affermava che il C è portabile quanto il Java, se non di più. un'altra sono io, che affermo che esistono metodologie di programmazione migliori del TDD, metodologie che evidentemente nessuno adotta perché inizialmente troppo costose (me lo spiego così), perciò tutti si cullano con questo favoloso e mirabolante TDD che è sicuramente molto meglio che scrivere codice errato, portarsi avanti gli errori e sprecare miliardi di ore a cercare bug apparentemente inesistenti che non verranno mai alla luce e che ti costringeranno ad eliminare i pezzi del programma uno alla volta fino a che non ti rimane solo la parte che non funziona (quando finalmente il codice ricomincerà a funzionare saprai di aver appena eliminato quello che non andava e avrai avuto la meglio sul bug, ma il TDD di certo è più conveniente).


Code Complete 2 affronta questo argomento e riporta gli studi in dettaglio fornendone i dati.
Microsoft per ogni programmatore ha un altro programmatore che scrivere gli integration test e parte dei programmer's test: se non fosse una pratica produttiva e non gli costasse meno, non lo farebbero. ok, ci credo, ma in futuro è meglio che non prendi Microsoft come esempio, che è notoriamente di una lentezza esasperante :D
credo che la velocità sia qualcosa su cui Zio Bill non investe granché, d'altra parte alla fine se guardi bene non ce n'è neanche motivo: lui si culla sugli allori, il suo trono non glielo toglie nessuno, hai il monopolio, tutto il resto è chiacchiere. solo qualche strano fenomeno da baraccone come FireFox potrebbe mettergli a rischio i miliarducci, e in tal caso Zio Bill si spaventa un po' e smuove il suo bel culone (vedi IE7), dopodiché quando tutto torna alla normalità può riaccomodarsi sugli allori e ordinare dell'altro nettare e ambrosia.


Non e' cosi' facile [...] aspetta un secondo, non andare predicando di non fare cose per le quali sei maestro :D
se non è questo un bel "giudizio affrettato", non lo è nessun'altro: non hai mai sperimentato lo "scrivere codice immediatamente senza errori", tutt'al più con qualcosa di assolutamente evidente che puoi cambiare immediatamente, ma stai giudicando questo metodo come impraticabile, impossibile. perché dici che lo è? è un giudizio empirico, nessuno ti ha detto e dimostrato che lo è, anche perché in teoria non lo è. cosa dovrebbe renderlo impossibile? il fatto che tu non sappia fin dal principio qual'è il codice corretto? questo è un problema; la soluzione è: sappilo. concettualmente nella tua testa ti farai un'idea del programma che deve essere sviluppato (o della parte che devi sviluppare); questa parte sarà divisa in più parti (metodologia top-down), e il problema verrà scomposto in problemi più semplici; fatti degli schemi su carta se necessario, ma penso che nella maggior parte dei casi non sia necessario (non credo che nel mondo del lavoro venga richiesto a una sola persona di sviluppare un progetto talmente vasto da non poterne avere un'idea completa a mente, da dover costringere a scrivere su carta); alla fine comunque dovresti arrivare a sapere esattamente cosa devi scrivere, cosa te lo impedisce? non sai come implementare alcune cose? e allora che programmatore sei? :p non sai con esattezza quali siano le specifiche? chiedi chiarimenti! non si può pretendere che lavori senza sapere quello che devi fare. detto questo: scrivi. (e qui si applica il discorso degli stereotipi).


Ma poi il tontolone e' in grado di ripetere quel test automaticamente migliaia di volte piu' velocemente di quanto possa farlo io, facendomi risparmiare tempo secondo quanto dico io tutti i tuoi test non li fai ne' una volta ne' mille :)
non fai altro che avviare il programma normalmente e vedere se funziona; lo usi in tutti modi possibili che ti vengono in mente, e vedi se ha i comportamenti aspettati; e tutto questo lo fai una volta sola alla fine della scrittura del tuo codice; se sei stato bravo (cioè se il codice l'hai scritto fin da subito senza errori, salvo sciocchezze immediatamente visibili), non devi fare nessun test e nessun debug. è all'incirca così che lavoro io, e mi trovo benissimo; tutto il test lo faccio alla fine, durante la scrittura faccio solo qualche... "mini-test", chiamiamoli così: avvio il prog. una volta sola per vedere se ho implementato correttamente funzionalità molto specifiche; cose molto rapide, semplicemente avvio e vedo se fa come mi aspetto. è durante i mini-test che può servire il debugger: se un "mini-test" mi fallisce analizzo il sorgente, ma se l'errore è un "osso duro" uso il debugger; da tempo immemore non mi capita di non riuscire a trovare un bug col debugger del Visual Studio. diciamo che i mini-test servono ad eliminare il rischio che ti ritrovi alla fine del lavoro col programma che non funziona e non so perché; a volte mi è capitato, ma il debugger ha sempre risolto le mie situazioni, e cosa più importante di tutte, ho imparato.


Ti ripeto, questo non e' un giudizio, questo e' un fatto. Fare testing e' piu' produttivo, resta da discutere se sia meglio scrivere i test prima o dopo il codice, ma non si discute sul fatto che e' piu' produttivo scrivere i test che non scriverli. E' un fatto provato. io non ci credo, innanzitutto perché non può essere provato se non su basi statistiche (e la statistica si sa, per definizione è un'opinione :D); che io non ci creda è tanto lecito quanto lo è che VICIUS affermi la superiore portabilità del C rispetto a quella del Java.


Se ti accorgi di un cambiamento, ma se non te ne accorgi e se ne accorge solo l'utente finale?
Ore e ore di debugging, quando un semplice test ripetuto ogni qualche minuto te lo avrebbe detto immediatamente. ora aldilà di tutto ore e ore di debugging non le ho mai fatte... :confused: anche solo per il fatto che se un debugger non riesce a dirmi dov'è che sbaglio entro mezz'ora/tre quarti d'ora, io stacco, faccio qualche sollevamento, passo qualche ora al tel con qualche amico (:D :p :p), e ripiglio probabilmente il giorno dopo :D
ma ORE di debugging non le ho mai fatte... :confused:


In teoria e' impossibile scrivere codice esente da difetti. sicuro? e perché?


E lo e' anche in pratica. Guarda, ho commesso molti piu' errori di quanti tu ne puoi anche immaginare ;) e non impari mai? mio buon amico, sbagliare è più che lecito, ma l'importante è sbagliare una volta sola; se per te non è così vuol dire una cosa sola: questo dannato TDD ti culla troppo :p
va bene il lavoro, ma da quanto ho capito fai anche dei programmi x conto tuo, x hobby: durante questi lavori fatti x hobby cerca di diventare indipendente da questo TDD; seriamente: provaci! prova a scrivere un programma perfetto! ricordati di liberare correttamente tutta la memoria che hai allocato, controlla sempre le condizioni dei tuoi cicli, controlla sempre che le variabili che usi in quelle condizioni abbiano esattamente i valori che ti aspetti. sbaglierai, è chiaro, ma man mano che sbagli, cerca di non sbagliare più; quando sbagli mi sembra la cosa più ovvia da fare, no?


Ed e' giusto imparare dagli errori, ma anche avendo esperienza infinita, resta il problema che non puoi conoscere la soluzione al problema a priori fino a che non inizi a implementarla. certo che puoi: devi fare questo: per farlo hai bisogno di quello e quell'altro; quello di fa così e quell'altro cosà. a questa cosa io continuerò a crederci finché non mi fai un esempio che me la smonta :)


Non puoi pensare di scrivere centinaia di righe di codice e pensare che funzionino senza errori. E' impossibile. Puoi scrivere un po', verificare che quel funziona, scrivere un altro po', verificare quell'altro po' funziona. li ho appena battezzati "mini-test"; che hanno che non vanno? rallentano solo se falliscono; ma nella maggior parte dei casi non devono fallire!! possono fallire solo per le cavolate che vedi subito.


La differenza e' che tu lo verifichi a mano, io lo faccio verificare al computer automaticamente in una frazione del tempo, per questo vado piu' spedito. vai più spedito perché quello che io faccio premendo F5 tu lo fai scrivendo altro codice e poi premendo F5? :)


E no... e no... e no... e proprio no... :)
Se non sai che cosa sia il refactoring, allora non hai esperienza di alcun tipo :)
(Lo dico in senso buono, non ti offendere). [...] non mi offendo, ma letta la spiegazione ti faccio presente che so bene a cosa ti riferivi con refactoring, solo che non sapevo si chiamasse così!! :)

71104
13-06-2005, 02:32
signori moderatori :p
ultimamente io e fek ci scambiamo delle pergamene di post di eccezionale lunghezza :D
e ho riscontrato un problema (credo anche lui): il forum non mi permette di mettere il numero di emoticons che vorrei. capisco l'imposizione del limite massimo (per evitare post idioti di sole emoticons), ma propongo una modifca nel calcolo del numero massimo di emoticons: il numero dovrebbe essere calcolato non con un hard limit, ma in relazione alla lunghezza del post; cioè, sarebbe meglio calcolare prima il rapporto tra parole scritte ed emoticons del messaggio, e poi imporre un hard limit su quello.
grazie :)

VICIUS
13-06-2005, 08:57
[...] vorrei dire scemenze ^^) VICIUS, che affermava che il C è portabile quanto il Java, se non di più. un'altra sono io, che affermo che esistono metodologie di programmazione mi[...]

[...] io non ci credo, innanzitutto perché non può essere provato se non su basi statistiche (e la statistica si sa, per definizione è un'opinione :D); che io non ci creda è tanto lecito quanto lo è che VICIUS affermi la superiore portabilità del C rispetto a quella del Java.[...]
Che fai mi usi come precedente? :D

In ogni caso io ricordo bene quella discussione e si paralava di C++/Java e non affermavo mai la superiorità di nessuno dei due. Dicevo semplicemente che il linguaggio _C++_ secodno me non era _meno_portabile_ di Java (sullo stesso livello). Lunico punto a vantaggio di Java era l'immensa libreria a disposizione. Se C++ avesse a disposizione un numero di librerie standard simile non ci sarebbero grandi problemi. Anche ora segliendo le librerie giuste (Qt ?) e progettando il sorgente nel modo giusto un programma in C++ puo andare tranquillamente su win, mac, *nix e qulche sistema embedded (probabilmente pure su alcuni sistemi strani in cui la jvm non è disponibile ma qui non ci giurerei :)).

In ogni caso il problema di fondo di quella discusione era semplicemente che avevamo/abbiamo una concezione diversa di portabilità. Per me un programma è portabile quando è possibile eseguirlo semplicemente ricompilandolo magari apportando qualche picolla modifica. Per te doveva essere compialto una sola volta ed eseguito su tutti i sistemi senza mai modificare sorgenti.

ciao ;)

cionci
13-06-2005, 08:58
Non si può :boh: O meglio, se ti sente Edivad82 ti mangia :D

Comunque anche io sono concorde con VICIUS ;)

VICIUS
13-06-2005, 09:06
sicuro? e perché?
Perchè non ci sei soltanto tu :) Quello che voglio dire è che: anche supponendo che tu sia in grado di scrivere codice perfetto e senza bug, nel momento in cui andrai a lavorare in un team il tuo codice verra a contatto con codice bacato di altri programmatori. Se prima la tua funzione andava e ora non va piu non è detto che sia il tuo codice la causa. Potrebbe essere un errore di un altro programmatore che sbaglia a passarti un parametro. Fidarsi è bene ma non fidarsi è meglio ! (defensive programming) ;) In questo caso il test servirebbero non solo a te ma anche agli altri programmatori.

ciao ;)

cionci
13-06-2005, 09:22
Infatti...con i test tu dimostri che il tuo codice è esente da errori perchè fa ciò che gli è stato richiesto !!!

^TiGeRShArK^
13-06-2005, 10:30
ok x quanto riguarda la duplicazione riguardandomi un'attimo il codice ho visto come doveva essere (Prima di vedere la soluzione di cionci :p).
X quanto riguarda la possibilità di scrivere codice privo di bug, come già detto da fek, è una pura utopia.
X quanto tu possa avere esperienza,71104,mi sa ke non hai visto veramente niente della programmazione su progetti veramente complessi... e non parlo certo di quelle skifezzuole ke fanno fare all'univ.
Io oramai sono 15 anni ke programmo in una marea di linguaggi diversi.... e credo ancora di essere veramente un cesso di programmatore.
Sto imparando moltissimo con l'esperienza, ma mi accorgo ke c'è sempre da imparare......
d'altronde scrivere un programma assolutamente privo di errori è impossibile perkè siamo umani, quindi x definizione non perfetti. Inoltre... se già in un libro ci accorgiamo subito di errori ed errori.... e su un libro ci lavorano x correggerli ed è pure ovviamente più facile trovare gli errori....immaginati in programmi di decine di migliaia di righe di codice, in cui magari ognuno si cura una parte e la parte ke sta curando qualcun'altro potrebbe causare dei problemi nella tua parte.
Io finora ho sempre usato metodi di sviluppo tradizionali, ma mi sono reso conto ke si perde davvero molto tempo x fare funzionare il tutto correttamente....soprattutto quando le specifike ti cambiano al volo...:muro:
vabbè torno a lavorare prima ke mi spakkano....

BYEZ!

fek
13-06-2005, 10:37
hai ragione, ho detto male: non mi riferivo al giudizio che do alla pratica del TDD, ma a come giudico il mio metodo :p cioè non fare TDD; ma siccome il mio metodo lo giudico buono e credo di dover utilizzare quello, l'altro lo considero da scartare ^^

No, tu ti riferisci ad una metodologia di scrittura del codice (TDD), che hai dimostrato di non conoscere e non aver mai imparato, quindi non puoi darci alcun giudizio.


ok, ci credo, ma in futuro è meglio che non prendi Microsoft come esempio, che è notoriamente di una lentezza esasperante :D

Microsoft e' uno degli sviluppatori di software piu' produttivi al mondo. E' giusto prenderli come esempio.
Un altra fra le migliori e piu' produttive aziende al mondo e' la ThoughtWorks (www.thoughtworks.com), nelle loro job description c'e' la richiesta esplicita di saper fare Refactoring, conoscere i Design Patter e saper scrivere Unit Testing; se non sai scrivere Unit Testing, non ti fanno neppure il colloquio :)

Dici che buttano soldi? E come loro sempre piu' aziende, e' un trend. Se vorrai fare il programmatore finita l'universita', dovrai imparare a scrivere Unit Test, altrimenti al massimo potrai aspirare al lavoretto nella piccola software house italiana.


aspetta un secondo, non andare predicando di non fare cose per le quali sei maestro :D
se non è questo un bel "giudizio affrettato", non lo è nessun'altro: non hai mai sperimentato lo "scrivere codice immediatamente senza errori", tutt'al più con qualcosa di assolutamente evidente che puoi cambiare immediatamente,


La stai andando un po' sul personale, evita :)
Ti ripeto che ho 15 anni di esperienza di cui 5 da professionista, le ho provate un po' tutte e non sono mai riuscito a scrivere codice senza errori perche' e' matematicamente impossibile. Lo sanno anche i sassi che il software esente da difetti non esiste.


ma stai giudicando questo metodo come impraticabile, impossibile. perché dici che lo è? è un giudizio empirico, nessuno ti ha detto e dimostrato che lo è, anche perché in teoria non lo è.


Proprio in teoria lo e', e' dimostrato matematicamente. Il numero di permutazioni degli input per un qualunque programma cresce esponenzialmente ed e' impossibile testare la correttezza della risposta per ogni possibile input. Quando non puoi provare la correttezza dell'output, l'output e' per definizione errato, quindi il programma contiene bug. La definizione vera e' piu' rigorosa.

cosa dovrebbe renderlo impossibile? il fatto che tu non sappia fin dal principio qual'è il codice corretto? questo è un problema; la soluzione è: sappilo. concettualmente nella tua testa ti farai un'idea del programma che deve essere sviluppato (o della parte che devi sviluppare); questa parte sarà divisa in più parti (metodologia top-down), e il problema verrà scomposto in problemi più semplici; fatti degli schemi su carta se necessario, ma penso che nella maggior parte dei casi non sia necessario (non credo che nel mondo del lavoro venga richiesto a una sola persona di sviluppare un progetto talmente vasto da non poterne avere un'idea completa a mente, da dover costringere a scrivere su carta); alla fine comunque dovresti arrivare a sapere esattamente cosa devi scrivere, cosa te lo impedisce? non sai come implementare alcune cose? e allora che programmatore sei? :p non sai con esattezza quali siano le specifiche? chiedi chiarimenti! non si può pretendere che lavori senza sapere quello che devi fare. detto questo: scrivi. (e qui si applica il discorso degli stereotipi).

Ingenuo :)

Scrivi un'applicazione che mi faccia il rendering di una scena importata da Maya, con un modello di illuminazione semplice di phong e supporti normal e specular map per ogni oggetto. Quanto ti serve, tre settimane? Ovviamente non deve avere nessun bug, perche' hai detto che tu sai scrivere software senza bug :)
Basta scriverlo top-down :) Farsi gli schemini su carta :)
Senza bug, ricorda, deve funzionare su ogni configurazione che trovo, in ogni condizione possibile e immaginabile, senza bug.
Vediamo se ci riesci. Io ti dico che non ci riuscirei, ma forse perche' io pretendo di lavorare senza sapere quello che faccio :)

Sai quanti bug l'EA prevede di trovare dalla fase di testing di BW2? 12.000. Te lo ripeto, 12.000. Piu' di 250 bug a testa. E' una previsione che fa in base a tutti gli altri progetti che l'EA ha sviluppato (sono centinaia). Second te all'EA nessuno sa programmare? Secondo te noi non sappiamo programmare senza scrivere bug? Perche' non vieni ad insegnarci a scrivere software senza bug :)

Il punto e' che finche' la tua esperienza si limita al software antispam, posso capire questi ragionamenti, ma quando ti auguro lavorerai professionalmente su software complesso con altre decine di persone, ti accorgerai quanto ingenua sia l'affermazione: "Ma basta scrivere senza bug e conoscere sempre la soluzione". Si', basta, peccato che sia impossibile :)

io non ci credo, innanzitutto perché non può essere provato se non su basi statistiche (e la statistica si sa, per definizione è un'opinione :D); che io non ci creda è tanto lecito quanto lo è che VICIUS affermi la superiore portabilità del C rispetto a quella del Java.

La statistica non e' un'opinione, e' una branca della matematica ed ha risposte esatte.
E' indifferente che tu ci creda o no, questo incidera' solo sulla tua carriera in futuro. E' un fatto comprovato che scrivere test e' piu' produttivo, non lo discutero' oltre. Se non ne se convinto, te ne convincerai con l'esperienza, se non te ne convincerai, non farai mai il programmatore ad un certo livello. E' davvero cosi' semplice.


ora aldilà di tutto ore e ore di debugging non le ho mai fatte... :confused:

Perche' non hai mai lavorato su progetti complessi. Noi abbiamo fatto notti di debugging.


e non impari mai? mio buon amico, sbagliare è più che lecito, ma l'importante è sbagliare una volta sola; se per te non è così vuol dire una cosa sola: questo dannato TDD ti culla troppo :p

Si', io imparo. Ti ho gia' detto di non andare sul personale :)

va bene il lavoro, ma da quanto ho capito fai anche dei programmi x conto tuo, x hobby: durante questi lavori fatti x hobby cerca di diventare indipendente da questo TDD; seriamente: provaci! prova a scrivere un programma perfetto!

Gia' fatto, anni fai, quando tu probabilmente non avevi ancora iniziato a programmare. E' impossibile.


li ho appena battezzati "mini-test"; che hanno che non vanno? rallentano solo se falliscono; ma nella maggior parte dei casi non devono fallire!! possono fallire solo per le cavolate che vedi subito.

Vanno benissimo, sono solo manuali, se fossero automatici risparmieresti solo molto tempo.


vai più spedito perché quello che io faccio premendo F5 tu lo fai scrivendo altro codice e poi premendo F5? :)

Ma io testo sempre tutto il programma con un solo F5 in meno tempo di quello che tu impieghi a testare solo una piccola parte. Se l'ultimo cambiamento che ho fatto rome qualcosa in una porzione del programma molto differente da quella su cui sto lavorando o nel codice di qualcun altro, io me ne accorgo subito, tu no. Se pensi che questo sia impossibile e basta scrivere codice senza errori, vuol dire che non hai abbastanza esperienza su progetti complessi.

^TiGeRShArK^
13-06-2005, 11:04
vuol dire che non hai abbastanza esperienza su progetti complessi.
:O è proprio questo il punto secondo me.

fek
13-06-2005, 11:45
:O è proprio questo il punto secondo me.

Ma sai che cosa mi fa sorridere? :)

Che mi dicono che e' possibile imparando con l'esperienza scrivere codice senza bug e senza leak, basta solo ricordarsi di distruggere tutto. E io oggi devo passarmi la giornata al debugger alla ricerca di... memory leak in D3D causati da un team di programmatori 3d che ha 70 anni di esperienza totale. Mark lavorava su Syndicate e Dave su Populous, se qualcuno se li ricorda.

Ma forse non abbiamo abbastanza esperienza per scrivere codice senza bug...

^TiGeRShArK^
13-06-2005, 12:09
eh si ke me li ricordo :D
populous era il primo simulatore di divinità (l'antenato di B&W + o - :D) e syndicate era un macello in cui c'erano di mezzo sindacati, missioni segrete e nn mi ricordo ke altro.....
cmq nn li ho mai avuti io, ci giocavo ogni tnt da dei miei amici :fagiano:

x quanto riguarda l'esperienza x scrivere codice senza bug.... credo ke un paio di milioni di anni FORSE potrebbero bastare se l'uomo avesse una capacità di memoria illimitata :D

cionci
13-06-2005, 12:09
Mark lavorava su Syndicate e Dave su Populous, se qualcuno se li ricorda.
:ave: :ave: :ave: :ave:

ghiotto86
13-06-2005, 12:18
fek mi meraviglio di te che non sai programmare evitando i bug.
e no e no :D :D

cionci
13-06-2005, 12:23
Mark lavorava su Syndicate e Dave su Populous, se qualcuno se li ricorda.
Tra l'altro sono entrambi della Bullfrog... Syndicate era di una difficoltà assurda...bel gioco :)

fek
13-06-2005, 12:49
fek mi meraviglio di te che non sai programmare evitando i bug.
e no e no :D :D

Almeno sono in buona compagnia :D

ghiotto86
13-06-2005, 13:35
e già :D
cmq molto interessante la spece di tutorial che hai fatto, non ero proprio a conoscenza di una metodologia del genere.
la teoria penso la farò ad ingegneria del software tra 2 anni (speriamo).

p.s. volevo chiederti: ma hai fatto ing informatica???

fek
13-06-2005, 13:53
e già :D
cmq molto interessante la spece di tutorial che hai fatto, non ero proprio a conoscenza di una metodologia del genere.


Sto scrivendo a tempo perso una serie di articoli sulle D3D sulla falsa riga di quei post. Quando ho qualcosa di presentabile magari ve la passo e mi fate una review a caccia degli errori?

p.s. volevo chiederti: ma hai fatto ing informatica???

Si', Ing. Informatica a Torino con specializzazione in Ing. del Software.

ghiotto86
13-06-2005, 15:04
Sto scrivendo a tempo perso una serie di articoli sulle D3D sulla falsa riga di quei post. Quando ho qualcosa di presentabile magari ve la passo e mi fate una review a caccia degli errori?ma certo. anche se ci sono pareri molto più professionali dei miei :bimbo:



Si', Ing. Informatica a Torino con specializzazione in Ing. del Software.
ne ero sicuro.

cionci
13-06-2005, 15:54
Sto scrivendo a tempo perso una serie di articoli sulle D3D sulla falsa riga di quei post. Quando ho qualcosa di presentabile magari ve la passo e mi fate una review a caccia degli errori?
Ma li stai scrivendo per qualche sito ? Altrimenti nella sottosezione delle guide ci starebbero molto bene :)

fek
13-06-2005, 16:08
Ma li stai scrivendo per qualche sito ? Altrimenti nella sottosezione delle guide ci starebbero molto bene :)

Beh, si' :)
Spero di presentarli al GDC dell'anno prossimo.

Pero' appena ho finito magari scrivo qualche guida per voi. Mi farebbe piacere. Ne parliamo.

mjordan
14-06-2005, 04:23
Fek, ti faccio una domanda provocatoria. :D
Alla fine della storia, avrai imparato anche "cosa vuol dire avere pazienza"? :sofico:

"Fermo! Non sappiamo nuotare!"
"Sarai buono o cattivo? Una benedizione o una maledizione? Sarai quello che vorrai essere".

Io forse sono uno dei pochi che ha giocato a Black & White due giorni di fila senza dormire e sono andato in ospedale perche' mi e' venuta una flebite ad un piede perche' stando seduto troppe ore ho avuto problemi di circolazione cardiaca. Alla fine non avevo capito che Dio ero, pero' quello mio se n'e' andato tutto :sofico:

ri
14-06-2005, 08:47
io non riesco a capire una cosa sola... se sto scrivendo software, nello specifico una determinata classe, scrivo i metodi che la compongono, però non mi limito a scrivere i soli metodi, ma scrivo anche la parte di codice che effettivamente li utilizza, scoprendo immediatamente se il progetto compila o meno.
Questo probabilmente accade perchè lavoro nella "piccola azienda italiana di software" e difficilmente si lavora in più di due persone sullo stesso progetto..

Comunque, queste unità di testing servono esclusivamente quando si sviluppa del codice altamente specializzato per un determinato compito e non si ha l'ambiente finale in cui verrà incluso, giusto?

cionci
14-06-2005, 09:35
Servono quando c'è una specifica vera e propria per ogni modulo... Cioè quando ci si è seduti prima a tavolino e si sono definite le specifiche e le interfacce di ogni modulo... Altrimenti come fai a scrivere il programma di test ???? :D

ri
14-06-2005, 10:54
ovvero serve in un mondo diverso dalla "piccola azienducola italiana di software", dove tutto cambia ogni 10 minuti

dovevo fare il falegname..

fek
14-06-2005, 11:24
Servono quando c'è una specifica vera e propria per ogni modulo... Cioè quando ci si è seduti prima a tavolino e si sono definite le specifiche e le interfacce di ogni modulo... Altrimenti come fai a scrivere il programma di test ???? :D

Non necessariamente, anzi no. Quelli sono i customer test che hanno lo scopo di verificare le specifiche funzionali dell'applicazione.

Il cliente chiede: "Quando inserisco un nome dell'autore non corretto, l'articolo non va salvato, altrimenti viene salvato con la data di oggi".

E "qualcuno" traduce questo requisito in un test non necessariamente nel linguaggio usato per implementare l'applicazione; di solito si usa un qualche linguaggio di scripting ad alto livello.

A quel punto il programmatore riceve il customer test e inizia a implementare. Vediamo, dice che un articolo va salvato, quindi dovra' essere possibile salvare un articolo in un qualche database. Prima serve poter aprire un database. Ecco un test. Lo implemento. Poi serve salvare un articolo nel database. Ecco un altro test. Implemento anche questo. Poi serve salvarlo con la data odierna. Ecco un altro test e la sua implementazione. Adesso mi serve capire se un nome dell'autore e' valido o meno riguardo ad un qualche criterio, scrivo il test relativo. Ora mi serve non scrivere l'articolo se il nome e' scorretto. Test.

Tutti i test passano? Si'
Il customer test passa? Si'.
Ho finito. E anche il cliente e' soddisfatto perche' vede passare il suo test e sa che io ho implementato il suo requisito. Se cambia il requisito, cambia il test e quando lo faccio passare di nuovo ho finito.

Quando ricevo il customer test sono di fronte ad un problema con una soluzione potenzialmente sconosciuta e non posso sapere quali programmer test mi porteranno alla soluzione corretta, allora inizio a scrivere il piu' semplice che mi venga in mente e che getti luce sulla soluzione, che mi porti piu' vicino. Man mano che scrivo test me ne verranno in mente altri, perche' ho sempre piu' chiara la soluzione. Quando il customer test passa, ho finito, non un minuto prima non uno dopo.

fek
14-06-2005, 11:28
Fek, ti faccio una domanda provocatoria. :D
Alla fine della storia, avrai imparato anche "cosa vuol dire avere pazienza"? :sofico:

Si' :(

cionci
14-06-2005, 11:44
Non parlo di sedersi al tavolino con il cliente, ma con il gruppo di programmatori... In pratica quando si ha davanti il progetto dell'applicazione...

fek
14-06-2005, 12:31
Non parlo di sedersi al tavolino con il cliente, ma con il gruppo di programmatori... In pratica quando si ha davanti il progetto dell'applicazione...

E' questo il punto. In queste metodologie agili non esiste piu' la fase in cui ci si siede tutti ad un tavolo e si butta giu' il design e l'architettura dell'applicazione e poi tutti a scriverla.

Si hanno un certo numero di "storie" che il cliente vuol vedere implementate in un certo ordine, ci si riunisce fra programmatori, si dividono le storie in task, si assegnano i tempi ai task e si parte subito a programmare. Il cliente nel frattempo scrive i suoi test per verificare che le storie siano implementate correttamente, i programmatori scrivono i propri test mentre implementano i propri task. Il design "emerge" dal continuo lavoro di refactoring, eliminazione delle duplicazioni, pulizia del codice e design che e' svolto mentre si programma. Niente documentazione con il design che gira, nessuno legge e dev'essere comunque mantenuta in sincronia. Il codice e i test sono la documentazione (e la piu' autorevole).

cionci
14-06-2005, 13:31
Molto interessante...ma come si fanno ad eliminare duplicazione fra task diversi ? In teoria non ci dovrebbero essere, ma mi sembra impossibile...

Ad esempio: mettiamo che serva una classe che scorre un file alla ricerca di una stringa...e ritorna tutto quello che c'è alla destra della stringa trovata fino in fondo alal riga..

Mettiamo che questo non sia un task primario, ma la necessità di questa classe spunta in due task distinti... Come si fa ad eliminare la duplicazione... Entrambi i task test sono corretti ed è corretto anche il customer test...

Altra domanda: chi definisce l'interfaccia fra i vari task ? Se un task necessità di un'altro task come si concorda l'interfaccia ? Bisogna anche adottare una sequenza di sviluppo...e chi la decide ? E quando ?

fek
14-06-2005, 13:52
Molto interessante...ma come si fanno ad eliminare duplicazione fra task diversi ? In teoria non ci dovrebbero essere, ma mi sembra impossibile...

Ad esempio: mettiamo che serva una classe che scorre un file alla ricerca di una stringa...e ritorna tutto quello che c'è alla destra della stringa trovata fino in fondo alal riga..

Mettiamo che questo non sia un task primario, ma la necessità di questa classe spunta in due task distinti... Come si fa ad eliminare la duplicazione... Entrambi i task test sono corretti ed è corretto anche il customer test...

Il problema si risolve con il concetto di Global Code Ownership, ovvero, io non ho il mio codice e tu il tuo, ma io sono responsabile di tutto il codice e tu anche. Se trovo una duplicazione nel tuo codice mentre ci lavoro sopra, la elimino. Se trovo una duplicazione fra due porzioni di codice in due task diversi, la elimino. E lo faccio senza patemi d'animo perche' ho una batteria di unit e customer test che mi dicono se ho combinato qualche casino. E' qui che entra in gioco il tempo che si risparmia scrivendo i test :)

Immagina la situazione in cui sono ora invece, con una code base di qualche milione di righe di codice, se vedo una porizione di codice a cui gioverebbe un po' di refactoring, ho paura a farlo, perche' potrei rompere qualcosa e non ho testing automatico a dirmelo, dovrei mettermi a testare tutto il gioco. Meno refactoring, significa piu' duplicazioni, piu' codice da mantenere, piu' tempo da perdere nella manutenzione e nel debugging, un circolo vizioso.



Altra domanda: chi definisce l'interfaccia fra i vari task ? Se un task necessità di un'altro task come si concorda l'interfaccia ? Bisogna anche adottare una sequenza di sviluppo...e chi la decide ? E quando ?

L'interfaccia si definisce "parlando" durante l'assegnazione dei task o durante lo sviluppo. Se, ad esempio, io devo scrivere un task che ha a che fare col tuo codice, e' facile che scrivero' quel task assieme a te (Pair Programming) e faremo "emergere" il design mentre lo scriviamo.

La priorita' dei task deriva dalla priorita' delle storie che e' sempre definita dal cliente, e' lui che da valore economico alle feature ed e' lui che decide in quale ordine vuole vedere arrivare le feature. In questa metodologia non esiste il discorso: "Se scriviamo questa storia prima anche se e' richiesta dopo l'altra storia, la seconda storia sara' piu' veloce". Non sono i programmatori a dare valore economico alle storie quindi non sono loro a decidere l'ordine.

Per chi non se ne fosse ancora accorto, sto descrivendo l'Extreme Programming :D

mjordan
14-06-2005, 18:53
Dannazione sono arrivato tardi in questo thread :cry: Voglio leggerlo tutto dall'inizio ma ora non ho tempo.

Fek, per caso hai gia' consigliato dei must have books su questi argomenti, anche pratici? Ancora controllo il thread in rilievo, ma ce ne sono anche di pratici su questi argomenti? Scusate se chiedo qualcosa di gia' citato, dopo in caso mi siedo con calma a leggere il thread. :(

fek
14-06-2005, 18:55
Quello di Ron Jeffries e' una versione pratica di quello di cui parlo.
Poi c'e' "Extremme Programming: Embrace Change" di Kent Beck (che assomiglia molto a quello che ha scritto Test Driven Development, anzi... sembrano la stessa persona :p).