Sessió B1: Test Driven Development, C++, Accessors
Objectius
- Refrescar el llenguatge C++
- Definició de classes, accessors, visibilitat
- Formateig amb streams a memoria
- Referencies, punters i constness
- Introduir-se al desenvolupament dirigit pels testos (Test Driven Development)
- Entendre la necessitat dels estàndards de codificació
Exemple de test driven development
A classe implementarem "en viu" les primeres classes del nostre sistema: Track
i Album. De moment no us preocupeu gaire de com s'integrarà això amb la resta de sistema.
Us hem fet commit de un entorn de desenvolupament mínim al directori src dels vostres sandbox.
El directori src del sandbox ha de quedar de la següent manera:
- src/
- aquí posareu les classes que implementen el sistema, implementades per vosaltres (arxius hxx i cxx)
- src/TestsUnitaris/
- aquí posareu els tests unitaris (granularitat petita) que testegen les classes del src/. Aquests tests seran escrits per vosaltres, tot i que, en aquesta sessió us els donem.
- src/TestsFuncionals/
- aquí posareu els tests funcionals o d'aceptació (granularitat grossa), que testegen la funcionalitat del src/. Els tests funcionals fan de requeriments de sistemes. Aquests tests seran donats pels professors.
- src/externalLibs/
- aquí van els fitxers que pertanyen a llibreries que no desenvolupeu vosaltres. De moment teniu el framework de testeig i una petita llibreria que us facilitarà l'accés al sistema de fitxers.
C++
Si encara no l'heu fet, seguiu el tutorial pas a pas per refrescar conceptes de C++, contenidors STL i polimorfisme
A part, us recomanem molt que implementeu l'exercici (resolt) Factures en C++
de la col.lecció de problemes.
Manual de Referències del C++
La web www.sgi.com té una
bona guia de la STL
La web www.cplusplus.com té
una bona referència dels 'streams' de la STL
Estàndard de codificació
Estàndard de noms i del codi
Els exemples que us donarem seguiran aquest estàndar. I el
vostre codi també s'hi haurà d'ajustar.
- Nomenclatura estàndar:
(UnaClasse, _unAtribut,
variableLocal, unMetode).
- Noms de mètodes i variables auto-explicatius i sense
abreviacions críptiques.
- Accessors no booleans de lectura amb unAtribut() i
d'escriptura amb unAtribut(nouValor)
- Accesors booleans de lectura amb preguntes sobre l'estat o esència de l'objecte
esCreativeCommons(), estaDescatalogat(), haCaducat(), etc. i
d'escriptura amb imperatius cap l'objecte com ara
siguesCreativeCommons(), descataloga(),
caduca(), etc.
- Els mètodes dels testos seran una excepció a la regla de nomenclatura:
farem servir el '_' per separar el que estem testejant, i les condicions en que ho fem. Exemple: testAfegeixArtista_quanElNomDArtistaJaExisteix().
Accessibilitat dels membres
- Tots els atributs private (o protected
si està justificat)
- Escollir la visibilitat (private,
protected o public) més restrictiva possible
per els mètodes.
Implementant mètodes
- Mètodes curts, usant sortides ràpides en comptes d'if/elses aniuats (early exit)
- Els mètodes de consulta (getters), que no modifiquen l'estat (attributs)
de l'objecte receptor els declararem sempre constants amb un const al final
de la declaració
ReturnType myMethod(parameters) const
El compilador ens avisarà si dintre del mètode estiguèssim modificant els attributs
o cridant mètodes no const.
- Els paràmetres que siguin objectes no bàsics es passaran com a referència per a no copiar-los.
La referència serà constant si el receptor no requereix modificar l'objecte.
void myMethod(const Type & object)
Només podem cridar mètodes constants d'un objecte que rebem com a constant.
El compilador ens assegura que passant un objecte com a paràmetre d'aquest
mètode, no té efectes laterals sobre l'objecte passat.
- Els paràmetres o retorns que siguin bàsics no cal passar-los per referència,
donat que té un cost similar passar una adreça de memòria que un tipus bàsic.
float myMethod(int value)
- Feu servir referències constants per retornar objectes no bàsics que siguin membres.
const Type & myMethod() const { return _member; }
- Feu servir cópia per retornar objectes no bàsics que es crein localment dins del propi mètode
(a classe els anomenarem informalment getters per construcció).
Type myMethod() { Type result; ...; return result; }
La raó és que no podem retornar una referència a un objecte que deixarà d'existir
quan sortim del mètode.
- Quan el pas per paràmetre o el retorn implica una
transferència de la responsabilitat d'eliminar l'objecte (veure abaix el model de memòria),
per convenció, farem servir punters en comptes de referències.
Type * extreu(); // Transfereix al cridador un objecte que estava al receptor
Type * creaType() const; // Crea i transfereix al cridador (no toca el receptor)
void adopta(Type *); // Transfereix del cridador cap al receptor
void elimina(Type *) const; // Transfereix del cridador i destrueix
Model de memòria
A C++ no tenim un garbage collector que elimini els objectes.
Tot i que gran part dels objectes s'eliminen automaticament per mecanismes de pila.
-
Els objectes locals d'un mètode es destrueixen automaticament quan es surt del mètode.
-
Els membres no punters (ni referència) d'un objecte
es creen automaticament al constructor de l'objecte
i es destrueixen automaticament al destructor.
-
Els objectes creats amb new
necessiten ser eliminats a mà (delete).
Per això cal un xic de disciplina i unes convencions clares sobre com manegar
la responsabilitat d'eliminar l'objecte.
Convencions de gestió de memòria:
Testfarm: Monitorització automàtica de la qualitat del codi
La pàgina de testfarm monitoritza tots els vostres repositoris.
En particular mostra l'estat dels tests (verd o vermell), i el nombre de tests passant.
Hi anirem afegint noves funcionalitats com mètriques de codi.
Tasques
- Passeu un a un els tests unitaris que teniu, commentats,
a la carpetea src/TestUnitaris del subversion seguint les tècniques
del test driven development (TDD).
Això corresponen les classes Obra i Colleccio.
- Feu commit al subversion a cada pas a cada red, gren i refactor.
No tingueu por de comitejar algo que no esteu segurs que sera el cami.
Si camineu pel cami equivocat subversion permet tornar enrera i a més,
ho podreu seguir amb l'històric per repassar com ho heu fet.
- Desenvolupeu dirigits per testos una nova classe Autor amb TDD però ara fent els testos vosaltres.
- Aquesta classe tindrà dos atributs un que és el nom i un altre
de booleà que determina si es tracta d'un autor en nòmina o d'un independent.
- També tindrà un mètode de consulta 'descripcioCataleg'
que retorna una cadena composta a partir del nom, i una etiqueta '[en nomina]' o '[independent]' separats per un espai i finalitzats amb un salt de línia.
No us preocupeu si el format és exactament el que us diem.
A la seguent iteració hi haurà un test funcional
que ens ho especificarà millor i simplement adaptarem
els tests unitaris i el codi que en depen.