Robert C. Martin
Código limpio Manual de estilo para el desarrollo ágil de software
Título original: Clean code: A handbook of agile software craftsmanship Robert C. Martin, 2009 Traducción: José Luis Góe! Celador "lustraciones: Jeni##er $o%n&e ' (ngela )roo&s *ditor digital: +ci-i Colaboradores: Mario J. C. /-1*sa3ol4 5 Tu-re /-1"nglés4
/ara (nn Marie: *l 6erdadero aor de i 6ida.
Agradecimientos Agradecimientos Me gustaría dar las gracias a is dos artistas, Jeni##er $o%n&e 5 (ngela )roo&s. Jenni#er es la encargada de las iresionantes ilustraciones del inicio de cada caítulo 5 tabién de los retratos de $ent )ec&, 7ard Cunning%a, )8arne troustru, Ron Je##ries, Grad5 )ooc%, -a6e T%oas, Mic%ael eat%ers 5 el ío roio. (ngela se encarga de las ilustraciones internas de los caítulos. a reali!ado uc%os dibu8os ara í en los ;ltios a3os, incluidos uc%os de los del libro Agile Software Development: Principles, Patterns, and Practices. Tabién es i riogénita. n agradeciiento esecial a los re6isores )ob )ogetti, George )ulloc&, Je##re5 <6erbe5 5 esecialente Matt eusser. an sido increíbles. an sido inisericordes. an sido inuciosos. Me %an #or!ado al =>io ara reali!ar las e8oras necesarias. Gracias a i editor, C%ris Gu!i&o?s&i, or su ao5o, aliento 5 aistad. Gracias a todo el ersonal de la editorial, incluida Raina C%roba&, @ue se encargó de @ue #uera %onesto 5 culiera los la!os. Gracias a Mica% Martin 5 a todos los de At% Lig%t ???.At%lig%t.co4 or sus críticas 5 su ao5o. Gracias a todos los
tensión @ue debe tener una #unción. E, or ;ltio, darle las gracias or leer estos agradeciientos.
Prólogo
na de nuestras golosinas re#eridas en -inaarca es Ga-Jol , con un #uerte sabor a regali!, @ue constitu5e un coleento er#ecto ara nuestro %;edo 5 #río clia. /arte del encanto de Ga-Jol ara ara los daneses es la #rase @ue suele incluir en el en6oltorio. *sta a3ana coré un a@uete de dos 5 e encontré con este antiguo dic%o danés: rlighed i sm! ting er ikke nogen lille ting"
FLa %onestidad or las cosas e@ue3as no es algo enor. /er#ecto ara @ue lo @ue ensaba escribir. Las cosas e@ue3as iortan. *ste libro trata sobre %uildes reocuaciones cu5o 6alor dista uc%o de ser enor. Dios est# en los detalles, a#iró el ar@uitecto Lud?ig ies 6an der Ro%e. *sta cita recuerda arguentos conteor=neos sobre el ael de la ar@uitectura en el desarrollo de software, en esecial en el uni6erso =gil. )ob 5 5o %eos tenido esta con6ersación uc%as 6eces. E sí, ies 6an der Ro%e se #i8aba en la utilidad 5 la #ora ateoral de la construcción @ue sub5ace a las grandes creaciones ar@uitectónicas. /or otra arte, seleccionaba ersonalente los oos de todas las uertas de todas las casas @ue dise3aba. H/or @uéI /or@ue las cosas e@ue3as iortan. *n nuestro interinable debate sobre T--, )ob 5 5o coincidios en @ue la ar@uitectura del software desee3a una iortante labor en el desarrollo, aun@ue teneos di#erentes 6isiones de lo @ue esto signi#ica. *stas di#erencias carecen de iortancia, 5a @ue odeos acetar @ue los ro#esionales resonsables dedican arte de su tieo a lani#icar un ro5ecto antes de coen!arlo. coen!ar lo. Las nociones de dise3o controlado ;nicaente or ruebas 5 el código, roias de #inales de la década de 990, 5a no n o son 6=lidas. E la atención al detalle es un ilar #undaental de los ro#esionales, casi coo cual@uier 6isión. /or un lado, la r=ctica en los detalles otorga doinio a los ro#esionales, 5 auenta su con#ian!a ara la r=ctica a a5or escala. /or otra arte, el =s ínio #allo de construcción, una uerta @ue no cierre bien o un baldosín al colocado, acaba con el encanto del todo. -e eso se trata el código liio.
/ero la ar@uitectura es sólo una et=#ora del desarrollo de software 5 en concreto de la arte del software @ue o#rece el roducto inicial, de la isa #ora @ue un ar@uitecto entrega un edi#icio inaculado. o5 en día, el ob8eti6o es coerciali!ar r=idaente los roductos. Kuereos @ue las #=bricas #=b ricas rodu!can software a leno rendiiento. e trata de #=bricas %uanas, rograadores @ue iensan, @ue sienten 5 @ue traba8an ara crear un roducto. La et=#ora de la anu#acturación anu#actura ción es incluso =s e6idente en este ensaiento. Los asectos roducti6os de las #=bricas de autoó6iles 8aonesas #ueron una gran insiración ara eru. /ero incluso en la industria autoo6ilística, gran arte del traba8o no radica en la #abricación sino en el anteniiento, o =s bien en cóo e6itarlo. *n el software, el A0 or 00 o =s de lo @ue %aceos se denoina cuantitati6aente anteniiento, el acto de rearar. *n lugar de otar or la tíica costubre occidental de crear software de calidad, debeos ensar coo rearadores o ec=nicos. HKué iensan los directores 8aoneses de todo estoI *n 9, un en#o@ue de calidad denoinado T/M $otal Prod%ctive &aintenance o Manteniiento roducti6o total4 aareció en escena. e centraba en el anteniiento 5 no en la roducción. no de los ilares de T/M es el con8unto de rinciios denoinados , una serie de discilinas. *stos rinciios son en realidad la base Lean, otro conocido térino en la escena occidental, 5 cada 6e! =s resente en el undo del software. *stos rinciios no son ocionales. Coo indica ncle )ob, la r=ctica del d el software correcto re@uiere discilina. Bo siere se trata de %acer, de roducir a la 6elocidad ótia. La #iloso#ía inclu5e estos concetos: Seiri u u organización: *s #undaental saber dónde est=n las cosas, ediante en#o@ues coo el uso de nobres correctos. HCree @ue los nobres de los identi#icadores no son rele6antesI Lea los siguientes caítulos. Seiton o Seiton o sistematización: *>iste un antiguo dic%o norteaericano: un sitio ara cada cosa 5 cada cosa en su sitio. n #ragento de código debe estar donde eseraos encontrarlo en caso contrario, re#actorice %asta conseguirlo. Seiso o Seiso o limpieza: Mantenga liio el lugar de traba8o. HKué dicen los autores sobre inundar el código de coentarios 5 líneas @ue caturan %istorias o deseos #uturosI *liínelos. Seiketsu o Seiketsu o estandarización: *l gruo decide cóo antener liio el lugar de traba8o. HCree @ue este libro %abla sobre tener un estilo de código co%erente 5 una serie de r=cticas dentro del gruoI H-e dónde ro6ienen esos est=ndaresI iga le5endo. le5end o. Shutsuke o Shutsuke o disciplina: igni#ica ser discilinado en la alicación de las r=cticas 5 re#le8arlas en el traba8o 5 acetar los cabios. i aceta el reto, %a leído bien, el reto, de leer 5 lle6ar a la r=ctica este libro, odr= corender 5 areciar el ;ltio unto. (@uí nos acercaos a la raí! de la ro#esionalidad resonsable de una ro#esión @ue debería reocuarse del ciclo 6ital de un roducto. (l igual @ue anteneos coc%es 5 otras =@uinas, el anteniiento di6isible, eserar a @ue sur8an los errores, es la e>ceción. /or el contrario, ascendeos un ni6el: inseccionaos diariaente las =@uinas 5 arreglaos los coonentes gastados antes de @ue se roan, o cabiaos el aceite cada 6arios iles de &ilóetros ara e6itar robleas. *n el código, debeos re#actori!ar sin coasión. /uede ascender otro ni6el =s, coo %i!o el o6iiento T/M %ace 0 a3os: crear =@uinas @ue se ueden antener e8or. Crear código legible es tan iortante coo crear código e8ecutable. La r=ctica de#initi6a, @ue aareció en los círculos T/M en 9N0, es la @ue se centra en introducir nue6as =@uinas o
sustituir las antiguas. Coo red )roo&s nos ad6irtió, deberíaos re%acer el software cada siete a3os ara eliinar los robleas latentes. Tendríaos @ue actuali!ar este la!o or seanas, días e incluso %oras en lugar de a3os. (%í es donde se encuentra el detalle. *l detalle tiene un gran oder, 5 es un en#o@ue 6ital %uilde 5 ro#undo, coo es de eserar de cual@uier en#o@ue de origen 8aonés. /ero no es sólo la 6isión oriental de la 6ida tabién lo encontraos en el ueblo norteaericano. La cita seiton anterior ro6iene de la lua de un inistro de <%io @ue, literalente, consideraba la liie!a coo un reedio ara todas las #oras del al. HE seisoI 'a limpie(a es la p%re(a. (un@ue una casa sea bella, el obiliario inadecuado acaba con su encanto. HE la oinión de d e sh%ts%ke al resectoI )l *%e conf+e en lo pe*%eo confiar# en lo s%perior . HE la redisosición a re#actori!ar en el oento adecuado, re#or!ando nuestra osición ara las osteriores grandes decisiones, en lu8ar de de8arlo asarI na p%ntada a tiempo ahorra ciento" Al *%e madr%ga, Dios le a.%da" /o de0es para maana lo *%e p%edas hacer ho. éste era el sentido original de la #rase Fen el oento adecuado de Lean %asta @ue ca5ó en anos de consultores de software4. HE sobre calibrar la iortancia de los e@ue3os es#uer!os indi6iduales en un todo a5orI De pe*%eas semillas crecen grandes #rboles. HE la integración de sencillas tareas re6enti6as en la 6ida diariaI s vale prevenir *%e c%rar . *l código liio %onra las raíces de la sabiduría oular, de antes o de a%ora, 5 se uede alicar con atención al detalle. "ncluso en la literatura ar@uitectónica encontraos e8elos de estos detalles. /iense en los oos de ies 6an der Ro%e. *so es seiri. *s la atención a todos los nobres de 6ariables. -ebe bauti!ar a una 6ariable con el iso cuidado coo si #uera su riogénito. E coo todo sabeos, este cuidado no acaba nunca. *l ar@uitecto C%risto%er (le>ander, adre de atrones 5 lengua8es de atrones, considera todo acto de dise3o coo un e@ue3o acto local de rearación, 5 considera la aestría de la estructura coo coetencia ;nica del ar@uitecto las #oras a5ores se ceden a los atrones 5 su alicación a los %abitantes. *l dise3o es interinable no sólo al a3adir una nue6a %abitación a una casa, sino al restar atención a la intura, a cabiar las al#obras o a instalar un nue6o #regadero en la cocina. celencia. /uede @ue esto no sea nada nue6o, ero al leer este libro sentir= la necesidad de adotar discilinas rec%a!adas en su oento or aatía o or un deseo de esontaneidad o una sile resuesta al cabio. -esa#ortunadaente, no soleos considerar estas reocuaciones la cla6e del arte de la rograación. Renunciaos ronto a nuestro código, no or@ue lo %a5aos coletado, sino or@ue nuestro sistea de 6alores se centra en el #uturo =s @ue en la sustancia de nuestros roductos. *sto tiene un recio #inal: hierba mala n%nca m%ere. La in6estigación, ni en el undo industrial ni en el acadéico, se reduce a antener liio el código. Cuando traba8aba en la organi!ación )ell Labs o#t?are /roduction Researc% sin duda de roducción4 corobaos @ue un estilo de sangrado co%erente era uno un o de los a5ores indicadores estadísticaente signi#icati6os de una ba8a densidad de errores. Kuereos @ue una ar@uitectura, un lengua8e de rograación u otra noción suerior sea el oti6o de la
calidad coo seres cu5a suuesta ro#esionalidad se debe al doinio de %erraientas 5 étodos de dise3o, nos sentios insultados or el 6alor @ue los rograadores a3aden con tan sólo alicar un estilo de sangrado co%erente. /ara citar i roio libro de %ace O a3os, dic%o estilo distingue la e>celencia de la sile coetencia. La 6isión 8aonesa corende el 6erdadero 6alor del traba8ador cotidiano 5, en esecial, de los sisteas de desarrollo @ue deenden de las sencillas acciones diarias de tales traba8adores. La calidad es el resultado de un illón de acciones cuidadosas, no de un étodo agní#ico caído del cielo. Kue dic%as acciones sean siles no signi#ica @ue sean silistas, 5 uc%o enos @ue sean sencillas. on la base de la grande!a 5, cada 6e! =s, de cual@uier eresa %uana. "gnorarlas no es %uano en absoluto. *6identeente, toda6ía de#iendo el ensaiento global, en esecial el 6alor de los en#o@ues ar@uitectónicos cientados en el conociiento de los doinios 5 la caacidad de uso del software. *ste libro no 6ersa sobre esto, al enos no de #ora e6idente. *ste libro transite un ensa8e =s sutil cu5a ro#undidad no debe enosreciarse. Coincide con la 6isión de gente coo /eter oerlad, $e6lin enne5 5 Gio6anni (sroni, cu5os antras son F*l código es el dise3o 5 FCódigo sile. (un@ue debeos recordar @ue la inter#a! es el rograa 5 @ue sus estructuras dicen uc%o sobre la roia estructura del rograa, es #undaental adotar de #ora continuada la %uilde osición de @ue el dise3o 6i6e en el código. E aun@ue los cabios 5 la et=#ora de la #=brica suongan costes, los cabios de dise3o suonen 6alor. -ebeos considerar al código coo la articulación de los es#uer!os de dise3o, 6isto coo un roceso, no coo algo est=tico. *s en el código donde se desarrollan los concetos ar@uitectónicos de cone>ión 5 co%esión. i escuc%a a Larr5 Constantine describir la cone>ión 5 la co%esión, lo %ace en térinos del código, no desde concetos abstractos roios de ML. *n su ensa5o Abstraction Descant , Ric%ard Gabriel a#ira @ue la abstracción es el al. *l código es el reedio al al 5 el código liio uede @ue sea di6ino. ol6iendo a i ca8a de Ga-Jol , considero iortante recordar @ue la sabiduría danesa nos recoienda no sólo restar atención a las e@ue3as cosas, sino tabién ser honestos con ellas. *sto signi#ica ser %onesto con el código, con nuestros colegas sobre el estado del código 5, en esecial, con nosotros isos. Heos %ec%o todo lo osible ara de8ar las cosas e8or @ue coo las encontraosI Heos re#actori!ado el código antes de terinarloI Bo se trata de reocuaciones eri#éricas, sino @ue se encuentran en la base isa de los 6alores (gile. *n eru se recoienda @ue la re#actori!ación sea arte del conceto de Terinado. Bi la ar@uitectura ni el código liio insisten en la er#ección, sino en la %onestidad 5 en %acerlo lo e8or osible. )rrar es h%mano1 perdonar es divino. *n cru, todo lo %aceos de #ora 6isible. (ireaos los traos sucios. oos %onestos sobre el estado de nuestro código 5a @ue nunca es er#ecto. Bos %eos %ec%o =s %uanos, =s erecedores de lo di6ino 5 estaos =s ró>ios a la grande!a de los detalles. *n nuestra ro#esión, necesitaos deseseradaente toda la a5uda osible. i un suelo seco reduce el riesgo de resbalones 5 las %erraientas bien organi!adas auentan la roducti6idad, es nuestra eta. E en cuanto al libro, es la e8or alicación rag=tica de los rinciios Lean de software @ue %e 6isto nunca en #orato ireso. Bo eseraba enos de este gruo de indi6iduos @ue durante a3os se %an es#or!ado no sólo or e8orar sino en o#recer sus conociientos a la industria ediante obras coo la @ue a%ora tiene entre anos. ace @ue el undo sea un oco e8or @ue antes de @ue ncle )ob e en6iara el anuscrito.
E tras coletar este e8ercicio, e disongo a liiar i escritorio. James O. Coplien MPrdru, -inaarca
Introducción
Reroducido con eriso de T%o ol?erda. %tt:QQ???.osne?s.coQstor5Q92NNQ7Ts. S 200A ocus %i#t. HKué uerta reresenta su códigoI HKué uerta reresenta a su e@uio o a su eresaI H/or @ué estaos en esa %abitaciónI H*s una sencilla re6isión del código o %eos detectado un sin#ín de robleas terriblesI H-euraos resas del =nico el código @ue ens=baos @ue #uncionabaI HLos clientes %u5en desa6oridos 5 los directores direc tores nos isan los talonesI HCóo aseguraos de @ue abrios la uerta correcta cuando las cosas se onen #easI La resuesta: resues ta: la maestr+a. La aestría se consigue de dos #oras: conociientos 5 traba8o. -ebe ad@uirir el conociiento de los rinciios, atrones, r=cticas 5 %eurística roios de un aestro, 5 doinar dic%os conociientos a tra6és de la r=ctica. /uedo ense3arle la teoría de ontar en bicicleta. -e %ec%o, los concetos ate=ticos cl=sicos son u5 sencillos. Gra6edad, #ricción, 6elocidad angular, centro de asa, etc., se ueden deostrar en enos de una =gina releta de ecuaciones. Con esas #órulas, uedo deostrar @ue ontar en bicicleta es r=ctico 5 roorcionarle los conociientos necesarios ara conseguirlo. /ero la riera 6e! @ue se onte en una bici se caer= al suelo.
*l dise3o de código no es di#erente. /odríaos enuerar todos los rinciios del código liio 5 con#iar en @ue se encarg%e del resto es decir, de8ar @ue se ca5era de la bici4 ero entonces la regunta sería @ué clase de ro#esores soos 5 @ué clase de aluno sería. Bo. (sí no #unciona este libro. (render a crear código liio es complicado. Re@uiere algo =s @ue conocer rinciios 5 atrones. Tiene @ue sudar. -ebe racticarlo 5 #allar. -ebe 6er cóo otros ractican 5 #allan. -ebe obser6ar cóo có o se caen 5 recueran el aso. aso . -ebe 6er cóo agoni!an en cada decisión 5 el recio @ue agan or toar decisiones e@ui6ocadas. /ara leer este libro, re=rese a traba8ar duro. Bo es un libro @ue se ueda leer en un a6ión 5 terinarlo antes de aterri!ar. *ste libro le %ar= traba8ar, 5 uc%o. HE @ué tio de traba8oI Tendr= @ue leer código, en abundancia. E se le edir= @ue iense en @ué acierta el código 5 en @ué #alla. e le edir= @ue siga nuestras descriciones ientras deseda!aos ódulos 5 los 6ol6eos a ensablar. /ara ello necesitar= tieo 5 es#uer!o, ero creeos @ue erece la ena. eos di6idido el libro en tres artes. Los rieros caítulos describen los rinciios, atrones 5 r=cticas ara crear c rear código liio. "nclu5en abundante código 5 resultan di#íciles de leer. ir6en coo rearación a la segunda arte. i abandona tras leer la riera sección, @ue tenga buena suerte. La segunda arte del libro es la =s di#ícil. "nclu5e 6arios casos de estudio cu5a cole8idad 6a auentando. Cada e8elo es un e8ercicio de liie!a de código, trans#orar código con robleas ara @ue tenga enos robleas. *l detalle de esta arte es ab%ndante. Tendr= @ue alternar entre el te>to 5 los listados de código. Tendr= @ue anali!ar 5 entender el código, 5 corender el ra!onaiento de cada cabio reali!ado. /iense en @ue esta arte le llevar# varios d+as. La tercera arte del libro es un ;nico caítulo @ue contiene una lista de %eurística 5 síntoas de código erróneo smells smells4 con#eccionada al crear los casos r=cticos. (l anali!ar 5 liiar el código de los e8elos, docuentaos el oti6o de todas nuestras acciones coo %eurística o síntoa. "ntentaos corender nuestras reacciones al código @ue leíaos 5 odi#ic=baos, 5 nos es#or!aos or caturar las sensaciones @ue tu6ios 5 las decisiones @ue adotaos. *l resultado es una base de conociientos @ue describe cóo ensaos cuando creaos, leeos 5 liiaos código. *sta base de conociientos no le ser6ir= de uc%o si no lee atentaente los casos de la segunda arte del libro. *n esos caítulos %eos anotado con recisión todos los cabios reali!ados con re#erencias a la %eurística. *stas re#erencias se uestran entre corc%etes, coo 22U. -e este odo uede 6er el conte>to en el @ue se %a alicado 5 creado dic%a %eurística. Bo iorta tanto el roio 6alor de las %eurísticas sino la relaci2n entre ellas . las decisiones adoptadas al limpiar el c2digo en los e0emplos. i lee la riera 5 la tercera arte 5 se salta los casos r=cticos, %abr= leído otro libro distinto sobre cóo crear código correcto, ero si dedica tieo a anali!ar los casos, sigue todos 5 cada uno de los asos, cada una de las decisiones, si se one en nuestro lugar 5 se obliga a ensar tal 5 coo lo %icios nosotros, entonces corender= uc%o e8or todos los rinciios, atrones, r=cticas 5 %eurística. Ea no ser= un conociiento suer#icial. e con6ertir= en algo ro#undo. Lo integrar= de la isa #ora @ue una bicicleta se con6ierte en una e>tensión roia una 6e! doinada la #ora de ontar.
Sobre la imagen de cubierta La iagen de la ortada es M0V: la Gala>ia del obrero. M0V se encuentra en irgo, a unos W0 illones de a3os lu!, 5 su n;cleo es un s;er agu8ero negro @ue esa aro>iadaente il illones de asas solares. HLa iagen le recuerda la e>losión de la luna /ra>is de $lingonI Recuerdo la escena de tar Tre& " en la @ue se ostraba un anillo de restos #lotando tras la e>losión. Tras esa escena, el anillo se %a con6ertido en un eleento %abitual de las e>losiones de ciencia #icción. "ncluso se a3adió a la e>losión de (lderaan en ediciones osteriores de la riera elícula de La Guerra de las Gala>ias. HKué ro6ocó la #oración de este anillo alrededor de M0VI H/or @ué tiene un centro de tales diensiones 5 un n;cleo tan brillante 5 diinutoI /arece coo si el agu8ero negro central %ubiera ro6ocado un ori#icio de W0 000 a3os lu! en el centro de la gala>ia. La desgracia caería sobre las ci6ili!aciones @ue se encontraran en el caino de este desastre cósico. Los s;er agu8eros negros desa5unan estrellas 5 con6ierten arte de su asa en energía. *XMC2 uede bastar, ero cuando M es una asa estelar %a5 @ue tener cuidado. HCu=ntas estrellas %abr= engullido este onstruo antes de saciar su aetitoI *l taa3o del 6acío central odría ser una ista.
"agen de ortada: S it!et ace Telescoe. La iagen de M0V de la ortada es una cobinación de la #aosa #otogra#ía del ubble iagen suerior4 5 la reciente iagen de in#rarro8os del obser6atorio orbital it!er in#erior4. *sta ;ltia uestra claraente la #ora de anillo de la gala>ia. ( la lu!, sólo 6eos el borde #rontal de la silueta del anillo. La asa central oculta el resto. /ero en la iagen de in#rarro8os, las artículas calientes del anillo brillan a tra6és de
la asa central. Las dos i=genes cobinadas nos o#recen una 6ista desconocida %asta a%ora e ilican @ue %ace tieo era un auténtico in#ierno acti6o.
Código !impio
*st= le5endo este libro or dos oti6os. /or un lado, es rograador. /or otro, @uiere ser e8or rograador. /er#ecto. Becesitaos e8ores rograadores. *ste libro trata sobre rograación correcta. *st= releto de código. Lo anali!areos desde todas las direcciones. -esde arriba, desde aba8o 5 desde dentro. Cuando terineos, sabreos uc%o sobre código 5, en esecial sabreos distinguir entre código correcto e incorrecto. abreos cóo escribir código correcto 5 cóo trans#orar código incorrecto en código correcto.
"ágase el código e odría a#irar @ue un libro sobre código es algo obsoleto, @ue el código 5a no es el roblea 5 @ue deberíaos centraos en odelos 5 re@uisitos. a5 @uienes sugieren @ue el #inal del código est= ró>io. Kue los rograadores 5a no ser=n necesarios or@ue los eresarios generar=n rograas a artir de eseci#icaciones. Bo es cierto. *l código nunca desaarecer=, 5a @ue reresenta los detalles de los re@uisitos. *n alg;n ni6el, dic%os detalles no se ueden ignorar ni abstraer deben
eseci#icarse, 5 ara eseci#icar re@uisitos de #ora @ue un e@uio ueda e8ecutarlos se necesita la rograación. -ic%a eseci#icación es el código. *sero @ue el ni6el de abstracción de nuestros lengua8es siga auentando. Tabién esero @ue auente el n;ero de lengua8es esecí#icos de doinios. er= algo ositi6o, ero no eliinar= el código. -e %ec%o, todas las eseci#icaciones es eci#icaciones creadas en estos lengua8es lengua 8es de ni6el suerior 5 esecí#icos de los doinios ser=n código, 5 tendr= @ue ser riguroso, reciso, #oral 5 detallado ara @ue un e@uio ueda entenderlo 5 e8ecutarlo. *l @ue iense @ue el código 6a a desaarecer es coo el ate=tico @ue esera @ue un día las ate=ticas no sean #orales. *seran descubrir una #ora de crear =@uinas @ue %agan lo @ue @ueraos en lugar de lo @ue digaos. *sas =@uinas tendrían @ue entendeos de tal #ora @ue uedan traducir necesidades abiguas en rograas er#ectaente e8ecutados @ue satis#agan dic%as necesidades a la er#ección. *sto nunca suceder=. Bi si@uiera los %uanos, con toda su intuición 5 creati6idad, %an sido caaces de crear sisteas satis#actorios a artir de las sensaciones de sus clientes. *n realidad, si la discilina de la eseci#icación de re@uisitos nos %a ense3ado algo es @ue los re@uisitos bien eseci#icados son tan #orales coo el código 5 @ue ueden actuar coo ruebas e8ecutables de dic%o código. Recuerde @ue el código es b=sicaente el lengua8e en el @ue e>resaos los re@uisitos en ;ltia instancia. /odeos crear lengua8es @ue se asee8en a dic%os re@uisitos. /odeos crear %erraientas @ue nos eritan anali!ar 5 cobinar dic%os re@uisitos en estructuras #orales, ero nunca eliinareos la recisión necesaria or ello, siere %abr= código.
Código Incorrecto
Recienteente leí el rólogo del libro 3mplementation Pattern456 de $ent )ec&,
donde a#iraba @ue FYeste libro se basa en una #r=gil reisa: @ue el código correcto es rele6anteY. Hna fr#gil reisaI reisaI *n absoluto. Considero @ue es una de las =s robustas, aditidas e iortantes de nuestro sector 5 creo @ue $ent lo sabe4. abeos @ue el código correcto es rele6ante or@ue durante uc%o tieo %eos tenido @ue su#rir su ausencia. é de una eresa @ue, a #inales de la década de 9A0, creó una magn+fica alicación, u5 oular 5 @ue uc%os ro#esionales coraron 5 utili!aron. /ero los de los de ublicación ee!aron a distanciarse. Bo se corrigieron los errores entre una 6ersión 5 la siguiente. Crecieron los tieos de carga 5 auentaron los #allos. Toda6ía recuerdo el día en @ue aagué el roducto 5 nunca =s lo 6ol6í a usar. /oco desués, la eresa desaareció. -os décadas desués conocí a uno de los eleados de la eresa 5 le regunté sobre lo @ue %abía asado. La resuesta con#iró is teores. abían coerciali!ado el roducto antes de tieo con gra6es #allos # allos en el código. (l a3adir nue6as #unciones, el código eeoró %asta @ue 5a no udieron controlarlo. )l c2digo incorrecto f%e el motivo del fin de la empresa. H*n alguna ocasión el código incorrecto le %a suuesto un obst=culoI i es rograador seguraente sí. s í. -e %ec%o, teneos una alabra @ue lo describe: describe : sortear sortear . Teneos @ue sortear el código incorrecto. Bos arrastraos or una ara3a de !ar!as 5 traas ocultas. "ntentaos buscar el caino, una ista de lo @ue est= asando, ero lo ;nico @ue 6eos es =s 5 =s código sin sentido. in duda el código incorrecto le %a suuesto un obst=culo. *ntonces, Hor @ué lo escribióI HTenía risaI H/la!os de entregaI eguraente. /uede @ue ensara @ue no tenía tieo ara %acer un buen traba8o @ue su 8e#e se en#adaría si necesitaba tieo ara liiar su código. < uede @ue estu6iera cansado de traba8ar en ese rograa 5 @uisiera acabar cuanto antes. < @ue 6iera el traba8o endiente 5 tu6iera @ue acabar con un ódulo ara asar al siguiente. ( todos nos %a asado. Todos %eos 6isto el lío en el @ue est=baos 5 %eos otado or de8arlo ara otro día. Todos %eos sentido el ali6io de 6er cóo un rograa incorrecto #uncionaba 5 %eos decidido @ue un al rograa @ue #unciona es e8or @ue nada. Todos %eos dic%o @ue lo solucionaríaos desués. *6identeente, or a@uel entonces, no conocíaos la le5 de Le)lanc: Desp%7s es ig%al a n%nca.
#l coste total de un desastre i es rograador desde %ace dos o tres a3os, robableente %a5a su#rido los desastres coetidos or otros en el código. i tiene =s e>eriencia, lo %abr= su#rido en a5or edida. *l grado de su#riiento uede ser signi#icati6o. *n un eriodo de un a3o o dos, los e@uios @ue a6ancen r=idaente al inicio de un ro5ecto ueden acabar a aso de tortuga. Cada cabio en el código a#ecta a dos o tres artes del iso. Bing;n cabio es tri6ial. /ara aliar o odi#icar el sistea es necesario corender todos los detalles, e#ectos 5 consecuencias, ara de ese odo oder a3adir nue6os detalles, e#ectos 5 consecuencias. Con el tieo, el desastre auenta de tal odo @ue no se uede reediar. *s iosible. (l auentar este desastre, la roducti6idad del e@uio disinu5e 5 acaba or desaarecer. (l reducirse la roducti6idad, el director %ace lo ;nico @ue uede: aliar la
lantilla del ro5ecto con la eseran!a de auentar la roducti6idad. r oducti6idad. /ero esa nue6a lantilla no conoce el dise3o del sistea. Bo conocen la di#erencia entre un cabio adecuado al ob8eti6o de dise3o 5 otro @ue lo destroce. /or tanto, todos se encuentran soetidos a una gran resión ara auentar la roducti6idad. /or ello, coeten =s errores, auenta el desastre 5 la roducti6idad se acerca a cero cada 6e! =s 6éase la #igura .4.
$igura .. /roducti6idad #rente a tieo.
#l gran cambio de dise%o *n ;ltia instancia, el e@uio se rebela. "n#oran al director @ue no ueden seguir traba8ando con ese código. *>igen un cabio de dise3o. La dirección no re@uiere in6ertir en un cabio de dise3o del ro5ecto, ero no uede ignorar el ba8o ni6el de roducti6idad. (caba or ceder a las e>igencias de los rograadores 5 autori!a el gran cabio de dise3o. e selecciona un nue6o e@uio. Todos @uieren #orar arte del nue6o e@uio or ser un lien!o en blanco. /ueden ee!ar de cero 5 crear algo realente bello, ero sólo los e8ores ser=n elegidos ara el nue6o e@uio. Los de=s deben continuar con el anteniiento del sistea actual. (%ora los dos e@uios coiten. *l nue6o debe crear un sistea @ue %aga lo @ue el antiguo no uede. (de=s, deben asuir los cabios @ue continuaente se alican al sistea antiguo. La dirección no sustituir= el sistea antiguo %asta @ue el nue6o sea caa! de %acer todo lo @ue %ace el antiguo. *sta coetición uede durar uc%o tieo. Cono!co casos de casi 0 a3os. E cuando acaba, los iebros originales del e@uio nue6o %an desaarecido 5 los iebros actuales e>igen un cabio de dise3o del nue6o sistea or@ue es un desastre. i %a e>erientado alguna #ase de esta %istoria, 5a sabr= @ue dedicar tieo a @ue el código sea correcto no sólo es rentable, es una cuestión de suer6i6encia ro#esional.
Actitud H(lguna 6e! %a tenido @ue suerar un desastre tan gra6e @ue %a tardado seanas en lo @ue noralente %ubiera tardado %orasI Ha 6isto un cabio @ue debería %aberse reali!ado en una línea, alicado en cientos de ódulos distintosI on síntoas deasiado
%abituales. H/or @ué sucede en el códigoI H/or @ué el código de calidad se trans#ora tan r=idaente en código incorrectoI a5 uc%as e>licaciones. Bos @ue8aos de @ue los re@uisitos cabian de #ora @ue coroeten el dise3o original, de @ue los la!os de entrega son deasiado e>igentes ara %acer las cosas bien. Culaos a directores incoetentes, a usuarios intolerantes 5 a coerciales sin sentido. /ero la cula, @uerido -ilbert, es nuestra. Bo soos ro#esionales. /uede @ue resulte duro escuc%arlo. HCóo es osible @ue seamos responsables de tales desastresI HKué asa con los re@uisitosI HE los la!os de entregaI HE los directores incoetentes 5 los coerciales sin sentidoI HBo es tabién cula su5aI Bo. Los directores 5 los coerciales nos e>igen la in#oración @ue necesitan ara reali!ar sus roesas 5 coroisos, e incluso cuando no recurren a nosotros, no debeos tener iedo a decirles lo @ue ensaos. Los usuarios acuden a nosotros ara 6alidar la #ora de enca8ar los re@uisitos en el sistea. Los directores de ro5ectos acuden a nosotros ara deterinar los ob8eti6os. oos cólices en la rograación ro graación del ro5ecto 5 coartios gran arte de la resonsabilidad de los #allos, en esecial si tienen @ue 6er con código incorrecto. eguraente iense @ue, si no %ace lo @ue su 8e#e le dice, le desedir=n. *s irobable. Muc%os 8e#es sólo @uieren la 6erdad, aun@ue lo disiulen. Muc%os @uieren código correcto, aun@ue estén obsesionados con los ob8eti6os. /ueden de#ender aasionadaente los ob8eti6os 5 los re@uisitos, ero es su traba8o. *l n%estro es de#ender el código con la isa intensidad. /ara resuir, iagine @ue es édico 5 un aciente le e>ige @ue no se la6e las anos antes de una oeración or@ue se ierde deasiado tieo2U. *n este caso, el aciente es el 8e#e, ero el édico debe negarse negars e a lo @ue ide. H/or @uéI /or@ue el édico sabe =s @ue el aciente sobre los riesgos de in#ecciones. Bo sería ro#esional incluso sería ilegal4 @ue el édico cediera a las e>igencias del aciente. Taoco sería ro#esional @ue los rograadores cedieran a la 6oluntad de los 8e#es @ue no entienden los riesgos de un osible desastre.
#l enigma Los rograadores se en#rentan a un eniga de 6alores b=sicos. Los @ue tienen a3os de e>eriencia saben @ue un desastre ralenti!a su traba8o, 5 aun así todos los rograadores sienten la resión de d e coeter errores ara oder od er culir los la!os de entrega. *n de#initi6a, no toan el tieo necesario ara a6an!ar. Los 6erdaderos ro#esionales saben @ue la segunda arte del eniga no es cierta. Bo se cule un la!o de entrega coetiendo un error. er ror. -e %ec%o, el error nos ralenti!a de #ora inediata 5 %ace @ue no llegueos al la!o de entrega. La 8nica #ora de culirlo, la ;nica #ora de a6an!ar, es intentar @ue el código siere sea liio.
l arte del código limpio' "agine @ue cree @ue el código incorrecto es un obst=culo signi#icati6o. "agine @ue aceta @ue la ;nica #ora de a6an!ar es antener el código liio. *ntonces se reguntar= cóo crear código liio. Bo tiene sentido intentar crearlo si no sabe lo @ue es.
La ala noticia es @ue crear código liio es coo intar un cuadro. Muc%os sabeos si un cuadro se %a intado bien o no, ero oder reconocer la calidad de una obra no signi#ica @ue seaos intar. /or ello, reconocer código liio no signi#ica @ue seaos cóo crearlo. /ara crearlo se re@uiere el uso discilinado de iles de técnicas alicadas ediante un detallado sentido de la Fcorrección. *ste sentido del código es la cla6e. (lgunos nacen con este sentido.
Concepto de código limpio *>isten tantas de#iniciones coo rograadores. /or ello, %e consultado la oinión de conocidos 5 e>erientados rograadores. ()arne Stroustrup* in+entor de C,, - autor de The C++ Programming Language
&e g%sta *%e mi c2digo sea elegante . efica(" 'a l2gica debe ser directa para evitar errores oc%ltos, las dependencias deben ser m+nimas para facilitar el mantenimiento, el procesamiento de errores completo . s%0eto a %na estrategia artic%lada, . el rendimiento debe ser 2ptimo para *%e los %s%arios no tiendan a estropear el c2digo con optimi(aciones sin sentido" )l c2digo limpio hace bien %na cosa"
)8arne usa la alabra Felegante. Menuda alabra. eg;n el diccionario, Felegante signi#ica Fdotado de gracia, noble(a . sencille( . .
(arenteente )8arne iensa @ue el código liio es un lacer a la %ora de leerlo. u lectura debe %aceos sonreír, coo una ca8a de ;sica o un coc%e bien dise3ado. )8arne tabién enciona la e#icacia, en dos ocasiones. Bo debería sorrendeos 6iniendo del in6entor de CZZ ero considero @ue %a5 algo =s @ue el ero deseo de 6elocidad. Los ciclos algastados no son elegantes, no son un lacer. E #í8ese en la alabra eleada or )8arne ara describir la consecuencia de esta #alta de elegancia. sa tiendan. na gran 6erdad. *l código incorrecto tiende a auentar el desastre. Cuando otros cabian código incorrecto, tienden a eeorarlo. -a6e T%oas 5 (nd5 unt lo e>resan de #ora di#erente. san la et=#ora de las 6entanas rotasWU. n edi#icio con 6entanas rotas arece abandonado. E %ace @ue otros lo abandonen. -e8an @ue se roan otras 6entanas. * incluso las roen a roósito. La #ac%ada se ensucia con intadas 5 se acuula la basura. na 6entana rota inicia el roceso de la decadencia. )8arne tabién enciona @ue el rocesaiento de errores debe ser coleto, lo @ue se relaciona con la discilina de restar atención a los detalles. *l rocesaiento de errores abre6iado es una #ora de ignorar los detalles. istan tantos rinciios de dise3o de software @ue se uedan reducir a esta sencilla =>ia. Muc%os escritores %an tratado de counicar este ensaiento. *l código incorrecto intenta %acer deasiadas cosas 5 su coetido es abiguo 5 enre6esado. *l código liio es concreto. Cada #unción, cada clase 5 cada ódulo uestran una ;nica actitud @ue se antiene in6ariable 5 no se containa or los detalles circundantes. rad- (ooc/* autor de Object Oriented Analysis and Design with Applications
)l c2digo limpio es simple . directo" )l c2digo limpio se lee como %n te9to bien escrito" )l c2digo limpio no oc%lta la intenci2n in tenci2n del diseador, sino *%e m%estra n+tidas abstracciones . l+neas directas de control"
Grad5 antiene las isas ideas @ue )8arne, ero adota una ersecti6a de legibilidad . Me gusta esecialente @ue el código liio se ueda leer coo un te>to bien escrito. /iense en un buen libro. Recordar= @ue las alabras desaarecen 5 se sustitu5en or
i=genes, coo 6er una elícula. Me8or toda6ía. *s 6er los caracteres, escuc%ar los sonidos, e>erientar las sensaciones. Leer código liio nunca ser= coo leer )l Seor de los Anillos. /ero esta et=#ora literaria no es incorrecta. Coo una buena no6ela, el código liio debe ostrar de #ora clara el susense del roblea @ue %a5 @ue resol6er. -ebe lle6ar ese susense %asta un unto =lgido ara desués deostrar al a l lector @ue los robleas 5 el susense se %an % an solucionado de #ora e6idente. La #rase Fnítida abstracción de Grad5 es un o>íoron #ascinante. Bítido es casi un sinónio de concreto, con un otente ensa8e. *l código debe ser esecí#ico 5 no eseculati6o. ólo debe incluir lo necesario. Buestros lectores deben ercibir @ue %eos toado decisiones. 0(ig1 2a+e 3/omas* fundador de O3I* el padrino de la estrategia #clipse
)l c2digo limpio se p%ede leer . me0orar por parte de %n programador *%e no sea s% a%tor original" $iene pr%ebas de %nidad . de aceptaci2n" $iene nombres con sentido" frece %na . no varias formas de hacer algo" S%s dependencias son m+nimas, se definen de forma e9pl+cita . ofrece %na AP3 clara . m+nima" )l c2digo debe ser c%lto en f%nci2n del leng%a0e, .a *%e no toda la informaci2n necesaria se p%ede e9presar de forma clara en el c2digo"
)ig -a6e coarte el deseo de Grad5 de la legibilidad, ero con una iortante 6ariante. -a6e a#ira @ue el código liio #acilita las labores de e8ora de otros. /uede arecer e6idente ero no debeos debe os e>cedeos. -esués de todo, e>iste una di#erencia entre el código #=cil de leer 5 el código #=cil de cabiar. -a6e 6incula la liie!a a las ruebas. ace 0 a3os esto %ubiera ro6ocado cierta contro6ersia. /ero la discilina del -esarrollo controlado or ruebas %a tenido un gran iacto en nuestro sector 5 se %a con6ertido en uno de sus ilares. -a6e tiene ra!ón. *l código, sin ruebas, no es liio. "ndeendienteente de su elegancia, legibilidad 5 accesibilidad, si no tiene ruebas, no ser= liio.
-a6e usa dos 6eces la alabra m+nimo. alora el código de taa3o reducido, una oinión %abitual en la literatura de software desde su conceción. Cuanto =s e@ue3o, e8or. Tabién a#ira @ue el código debe ser c%lto, una re#erencia indirecta a la rograación de $nut%VU 5 @ue en de#initi6a indica @ue el código debe redactarse de una #ora legible ara los %uanos. Mic/ael $eat/ers* autor de orking !""ecti#ely with Legacy Code
Podr+a en%merar todas las c%alidades del c2digo limpio, pero ha. %na principal *%e engloba a todas ellas" )l c2digo limpio siempre parece *%e ha sido escrito por alg%ien a *%ien le importa" /o ha. nada evidente *%e hacer para me0orarlo" )l a%tor del c2digo pens2 en todos los aspectos posibles . si intentamos imaginar alg%na me0ora, volvemos al p%nto de partida . s2lo nos *%eda disfr%tar del c2digo *%e alg%ien a *%ien le importa realmente nos ha proporcionado"
na alabra dar iortancia. *s el 6erdadero tea de este libro, @ue incluso odría usar el subtítulo FC2mo dar importancia al c2digo. Mic%ael %a acertado de leno. *l código liio es a@uél al @ue se le %a dado iortancia. (lguien %a dedicado su tieo ara @ue sea sencillo 5 %a restado atención a los detalles. e %a reocuado. 4on Jeffries* autor de !$treme de !$treme Programming %nstalled - !$treme - !$treme Programming Ad#entures in C&
Ron coen!ó su carrera coo rograador con ortran en trategic (ir Coand 5 %a escrito código ara la r=ctica totalidad de lengua8es 5 e@uios. Merece la ena #i8arse en sus alabras: *n los ;ltios a3os, coencé 5 r=cticaente teriné con las reglas de código sile de )ec&. *n orden de rioridad, el código sile: *8ecuta todas las ruebas. Bo contiene dulicados. *>resa todos los concetos de dise3o del sistea. Minii!a el n;ero de entidades coo clases, étodos, #unciones 5 siilares. -e todos ellos, e @uedo con la dulicación. Cuando algo se reite una 5 otra 6e!, es una se3al de @ue teneos una idea @ue no acabaos de reresentar correctaente en el código. "ntento deterinar cu=l es 5, desués, e>resar esa idea con a5or claridad. /ara í, la e>resi6idad debe incluir nobres con sentido 5 esto5 disuesto a cabiar los nobres de las cosas 6arias 6eces. Con las odernas %erraientas de creación de código coo *clise, el cabio de nobres es u5 sencillo, or lo @ue no e suone roblea alguno. La e>resi6idad 6a =s all= de los nobres. Tabién e #i8o si un ob8eto o un étodo %acen =s de una cosa. i se trata de un ob8eto, robableente tenga @ue di6idirse en dos o =s. i se trata de un étodo, siere recurro a la re#actori!ación de e>tracción de étodos ara generar un étodo @ue e>rese con a5or claridad su coetido 5 6arios étodos secundarios @ue e>li@uen cóo lo %ace. La dulicación 5 la e>resi6idad son dos #actores @ue eriten e8orar considerableente código @ue no sea liio. in ebargo, e>iste otra cosa @ue tabién %ago conscienteente, aun@ue sea =s di#ícil de e>licar. Tras a3os en este traba8o, creo @ue todos los rograas est=n #orados de eleentos u5 siilares. n e8elo es la b;s@ueda de eleentos en una colección. "ndeendienteente de @ue sea una base de datos de registros de eleados o un aa de cla6es 5 6alores, o una atri! de eleentos, or lo general teneos @ue buscar un eleento concreto de esa colección. Cuando esto sucede, suelo incluir esa ileentación concreta en un étodo o una clase =s abstractos. -e ese odo dis#ruto de una serie de interesantes 6enta8as.
/uedo ileentar la #uncionalidad con algo sencillo, coo un aa %as%, or e8elo, ero coo a%ora todas las re#erencias a la b;s@ueda se ocultan en i e@ue3a abstracción, uedo odi#icar la ileentación siere @ue desee. /uedo a6an!ar r=idaente al tieo @ue conser6o la osibilidad de reali!ar cabios osteriores. (de=s, la abstracción de la colección suele catar i atención en lo @ue realente sucede e iide @ue ileente coortaientos de colecciones arbitrarias si lo @ue realente necesito es una #ora sencilla de locali!ar un eleento. Reducir los dulicados, a>ii!ar la e>resi6idad 5 dise3ar sencillas abstracciones en las #ases iniciales. /ara í, es lo @ue %ace @ue el código sea liio. *n estos bre6es =rra#os, Ron resue el contenido de este libro. Bada de dulicados, un ob8eti6o, e>resi6idad 5 e@ue3as abstracciones. Todo est= a%í. 5ard Cunning/am* in+entor de 5i6i* $it* - uno de los in+entores de la programación e7treme. 8no de los impulsores de los patrones de dise%o. 8na de las mentes tras Smalltal6 - la programación orientada a ob)etos. #l padrino de todos a los 9ue les importa el código.
Sabemos *%e estamos traba0ando con c2digo limpio c%ando cada r%tina *%e leemos res%lta ser lo *%e esper#bamos" Se p%ede denominar c2digo atractivo c%ando el c2digo hace *%e pare(ca *%e el leng%a0e se ha creado para el problema en c%esti2n"
*ste tio de a#iraciones son características de 7ard. Las leeos, asentios 5 asaos a la siguiente. *s tan ra!onable 5 e6idente e6iden te @ue aenas arece ro#undo. ro#und o. "ncluso odeos ensar @ue es lo @ue eser=baos. /ero reste atención. FY resulta ser lo @ue eser=baos. HCu=ndo #ue la ;ltia 6e! @ue 6io un ódulo @ue #uera =s o enos lo @ue eserabaI HLo %abitual no es 6er ódulos colicados 5 enre6esadosI HBo es esta #alta de concreción lo %abitualI HBo est= acostubrado a intentar e>traer el ra!onaiento de un sistea ara llegar al ódulo @ue est= le5endoI HCu=ndo #ue la ;ltia 6e! @ue le5ó un código 5 asintió coo seguraente %a5a %ec%o al leer la a#iración de 7ardI 7ard esera @ue al leer código liio no le sorrenda. -e %ec%o, ni si@uiera tendr= @ue es#or!arse. Lo leer= 5 ser= r=cticaente lo @ue eseraba. er= e6idente, sencillo 5
atracti6o. Cada ódulo reara el caino del siguiente. Cada uno indica cóo se escribir= el siguiente. Los rograas liios est=n tan bien escritos @ue ni si@uiera se dar= cuenta. *l dise3ador consigue sili#icarlo todo enoreente, coo sucede con todos dise3os e>cecionales. HE la noción de atracti6o de 7ardI Todos %eos criticado @ue nuestros lengua8es no se %a5an dise3ado ara nuestros robleas. /ero la a#iración de 7ard %ace @ue a%ora la resonsabilidad sea nuestra. (#ira @ue el c2digo atractivo hace *%e el leng%a0e pare(ca creado para el problema. /or tanto, soos resonsables de @ue el lengua8e are!ca sencillo. Bo es el lengua8e el @ue %ace @ue los rograas are!can sencillos, sino el rograador @ue consigue @ue el lengua8e lo are!ca.
#scuelas de pensamiento
HE 5o ncle )ob4I HKué es ara í el código liioI *n este libro le contareos, con todo detalle, lo @ue 5o 5 is colegas ensaos del código liio. Le contareos lo @ue ensaos @ue %ace @ue un nobre de 6ariable, una #unción o una clase sean liias. /resentareos estas oiniones de #ora absoluta, sin disculaos. *n este unto de nuestra carrera, 5a son absolutas. on n%estra esc%ela de pensamiento del código liio. Los esecialistas de las artes arciales no se onen de acuerdo sobre cu=l es la e8or de todas, ni si@uiera sobre cu=l es la e8or técnica de un arte arcial. *s %abitual @ue los aestros de las artes arciales creen sus roias escuelas de ensaiento 5 los alunos arendan de ellos. -e esta #ora nació Gracie Ji% Jits%, creada e iartida or la #ailia Gracie en )rasil ;akkor.% Ji% Jits%, #undada e iartida or <&u5aa R5u%o en To&io o Jeet <%ne Do, #undada e iartida or )ruce Lee en *stados nidos. Los alunos de estas discilinas se suergen en las ense3an!as del #undador. e dedican a arender lo @ue su aestro les ense3a 5 suelen e>cluir las ense3an!as de otros aestros. -esués, cuando %an e8orado su arte, ueden con6ertirse en alunos de otro aestro di#erente ara aliar sus conociientos 5 su e>eriencia. (lgunos seguir=n e8orando sus %abilidades, descubriendo nue6as técnicas 5 #undando sus roias escuelas. Binguna de estas escuelas tiene la ra(2n absoluta ero dentro de cada una actuaos
coo si las ense3an!as 5 las técnicas #ueran correctas. -esués de todo, e>iste una #ora correcta de racticar a&&or5u Jiu Jitsu o Jeet $une -o, ero esta corrección dentro de una escuela deterinada no anula las ense3an!as de otra di#erente. "agine @ue este libro es una descrición de la )sc%ela de mentores del c2digo limpio. Las técnicas 5 ense3an!as iartidas son la #ora en la @ue racticaos nuestro arte. /odeos a#irar @ue, si sigue nuestras ense3an!as, dis#rutar= de lo @ue %eos dis#rutado nosotros, 5 arender= a crear código liio 5 ro#esional. /ero no coeta el error de ensar @ue soos los ;nicos @ue teneos ra!ón. *>isten otras escuelas 5 otros aestros tan ro#esionales coo nosotros, 5 su labor es arender de ellos tabién. -e %ec%o, uc%as de las recoendaciones del libro son contro6ertidas, seguraente no esté de acuerdo con uc%as de ellas 5 uede @ue rec%ace algunas de #ora de#initi6a. *s correcto. Bo soos la autoridad #inal. /ero, or otra arte, las recoendaciones del libro son algo en lo @ue %eos ensado uc%o. Las %eos arendido tras décadas de e>eriencia 5 ensa5o 5 error. /or lo tanto, esté o no de acuerdo, sería una l=stia @ue no areciara, 5 resetara, nuestro unto de 6ista.
Somos autores *l cao [aut%or de un Ja6adoc indica @uiénes soos. oos autores. E los autores tienen lectores. -e %ec%o, los autores son responsables de counicarse correctaente con sus lectores. La ró>ia 6e! @ue escriba una línea de código, recuerde @ue es un autor 5 @ue escribe ara @ue sus lectores 8u!guen su es#uer!o. eguraente se regunte @ué cantidad de código se lee realente 5 si la a5or arte del es#uer!o no se concentra co ncentra en crearlo. H(lguna 6e! %a reroducido una sesión de ediciónI *n las décadas de 9A0 5 990 teníaos editores coo *acs @ue controlaban cada ulsación de tecla. e odía traba8ar durante una %ora 5 desués reroducir la sesión de edición coleta coo una elícula a alta 6elocidad. Cuando lo %ice, los resultados #ueron #ascinantes. La a5or arte de la reroducción eran desla!aientos entre ódulos. =ob accede al m2d%lo" Se despla(a hasta la f%nci2n *%e tiene *%e cambiar" Se detiene . piensa en las posibles opciones" h, v%elve al inicio del m2d%lo para comprobar la iniciali(aci2n de %na variable" Ahora v%elve a ba0ar . comien(a a escribir" >a.a, borra lo *%e hab+a escrito" >%elve a escribirlo" 'o v%elve a borrar" )scribe algo diferente pero tambi7n lo borra" Se despla(a a otra f%nci2n *%e invoca la f%nci2n *%e est# modificando para comprobar c2mo se invoca" >%elve a s%bir . escribe el mismo c2digo *%e acaba de borrar" Se detiene" >%elve a borrar el c2digo" Abre otra ventana . e9amina las s%bclases" ?Se ha reempla(ado esa f%nci2n@
e %ace una idea. *n realidad, la roorción entre tieo dedicado a leer #rente a tieo dedicado a escribir es de =s de 0:. Constantemente teneos @ue leer código antiguo coo arte del es#uer!o de crear código nue6o. (l ser una roorción tan ele6ada, @uereos @ue la lectura del código sea sencilla, aun@ue eso coli@ue su creación. *6identeente, no se uede escribir código sin leerlo, de odo @ue si es m#s f#cil de leer ser# m#s f#cil de escribir escribir . *s una lógica sin escaatoria. Bo se uede escribir código si no se uede leer el código circundante. *l código @ue intente escribir %o5 ser=s #=cil o di#ícil de escribir en #unción de lo #=cil o di#ícil de leer @ue sea el código circundante. i @uiere a6an!ar r=idaente, terinar cuanto antes 5 @ue su código sea #=cil de escribir, %aga @ue sea #=cil de leer.
!a regla del (o- Scout Bo basta con escribir código correctaente. *l código debe liiarse con el tieo. Todos %eos 6isto @ue el código se corroe con el tieo, de odo @ue debeos adotar un ael acti6o ara e6itarlo. Los )o5 couts norteaericanos tienen una sencilla regla @ue odeos alicar a nuestra ro#esión: De0ar el campamento m#s limpio de lo *%e se ha encontrado4B6"
i todos entregaos el código =s liio de lo @ue lo %eos recibido, no se corroer=. Bo %ace #alta @ue la liie!a sea asi6a. Cabie el nobre de una 6ariable, di6ida una #unción deasiado e>tensa, eliine eleentos dulicados, sili#i@ue una instrucción i# couesta. He iagina traba8ar en un ro5ecto en el @ue el código me0orara con el tieoI HCree @ue %a5 otras ociones @ue uedan considerarse ro#esionalesI -e %ec%o, Hla e8ora continuada no es una arte intrínseca de la ro#esionalidadI
Precuela - principios *n uc%os asectos, este libro es una Frecuela de otro @ue escribí en 2002 titulado Agile Software Development: Principles, Patterns, and Practices ///4. \l libro /// trata sobre los rinciios del dise3o orientado a ob8etos 5 uc%as de las técnicas eleadas or desarrolladores ro#esionales. i no %a leído ///, corobar= @ue continua la %istoria contada en este libro. i lo %a leído, encontrar= uc%as de las sensaciones de ese libro reroducidas en éste a ni6el del código. *n este libro encontrar= re#erencias esor=dicas a distintos rinciios de dise3o coo R/ Single esponsibilit. Principle o /rinciio de resonsabilidad ;nica4,
Conclusión Los libros sobre arte no le roeten @ue se con6ertir= en artista. olaente ueden ostrarle %erraientas, técnicas 5 rocesos de ensaiento @ue otros artistas %a5an utili!ado. -el iso odo, este libro no uede roeter @ue se con6ierta en un buen rograador, @ue tenga sentido sen tido del código. ólo uede ostrarle los rocesos de ensaiento de buenos rograadores rograador es 5 los trucos, técnicas 5 %erraientas @ue elean. (l igual @ue un libro sobre arte, este libro est= releto de detalles. *ncontrar= uc%o código. er= código correcto 5 código incorrecto. er= código incorrecto trans#orado en código correcto. er= listas de %eurística, discilinas 5 técnicas. er= un e8elo tras otro. E desués de todo, ser= resonsabilidad su5a. HRecuerda el c%iste sobre el 6iolinista @ue se ierde caino de un conciertoI e cru!a con un anciano 5 le regunta cóo llegar al Teatro Real. *l anciano ira al 6iolinista 5 al 6iolín @ue lle6a ba8o el bra!o 5 le resonde: F/racti@ue 8o6en, racti@ue.
(ibliograf:a ;(ec6<=>: 3mplementation Patterns, $ent )ec&, (ddison17esle5, 200O. ;?nut/@>: 'iterate Programming , -onald *. $nut%, Center #or t%e tud5 o# Language and "n#oration, Leland tan#ord Junior ni6ersit5, 992.
Bombres con sentido or Ti
Introducción *n el software, los nobres son oniresentes. (arecen en 6ariables, #unciones, arguentos, clases 5 a@uetes. (signaos nobres a arc%i6os 5 a directorios, a arc%i6os 8ar, ?ar 5 ear. saos nobres constanteente. /or ello, debeos %acerlo bien. ( continuación, 6ereos algunas reglas b=sicas ara crear nobres correctos.
8sar nombres 9ue re+elen las intenciones *s #=cil a#irar @ue los nobres deben re6elar nuestras intenciones. Lo @ue @uereos recalcar es la importancia de %acerlo. *legir nobres correctos lle6a tieo, ero tabién a%orra traba8o. /or ello, reste res te atención a los nobres 5 c=bielos cuando encuentre otros e8ores. Todo el @ue lea su código se lo agradecer=. *l nobre de una 6ariable, #unción o clase debe resonder una serie de cuestiones b=sicas. -ebe indicar or @ué e>iste, @ué @ ué %ace 5 cóo se usa. i un nobre re@uiere r e@uiere un coentario, signi#ica @ue no re6ela su coetido. int d QQ tieo transcurrido en días
*l nobre d no re6ela nada. Bo e6oca una sensación de tieo transcurrido, ni de días. -ebe elegir un nobre @ue eseci#i@ue lo @ue se ide 5 la unidad de dic%a edida: int elasedTie"n-a5s int da5sinceCreation int da5sinceModi#ication int #ile(ge"n-a5s La elección de nobres @ue re6elen intenciones #acilita considerableente la corensión 5 la odi#icación del código. H/ara @ué sir6e el siguiente códigoI ublic List]intU^ getT%e4 _`Ob List]intU^ list X ne? (rra5List]intU^4 #or intU > : t%eList4 i# >0U XX V4 list.add>4 return list _`Od H/or @ué es colicado saber la #unción de este códigoI Bo %a5 e>resiones cole8as. Los esacios 5 el sangrado son ra!onables. ólo %a5 tres 6ariables 5 dos constantes. Bi si@uiera contiene clases cole8as o étodos oliór#icos, sólo una lista de atrices o eso arece4. *l roblea no es la silicidad del código sino su car=cter impl+cito: el grado en el @ue el conte>to no es e>lícito en el roio código. "lícitaente, el código re@uiere @ue seaos las resuestas a las siguientes reguntas: HKué contiene t%eListI HKué signi#icado tiene el subíndice cero de un eleento de t%eListI HKué iortancia tiene el 6alor VI HCóo se usa la lista de6ueltaI Las resuestas a estas reguntas no se encuentran en el código, ero se odrían %aber incluido. "agine @ue traba8a en un 8uego de buscar inas. *l tablero es una lista de celdas llaada t%eList. Cabieos el nobre or gae)oard. Cada celda del teclado se reresenta or edio de una atri!. *l subíndice cero es la ubicación de un 6alor de estado @ue, cuando es V, signi#ica @ue se %a detectado. (l asignar nobres a estos concetos e8oraos considerableente el código: ublic List]intU^ getlaggedCells4 _`Ob List]intU^ #laggedCells X ne? (rra5List]intU^4 #or intU cell : gae)oard4 i# cellT(T(L*U XX L(GG*-4 #laggedCells.addcell4 return #laggedCells _`Od La silicidad del código no %a cabiado. igue teniendo los isos oeradores 5 constantes 5 el iso n;ero de ni6eles anidados, ero a%ora es uc%o =s e>lícito. /odeos crear una sencilla clase ara celdas en lugar de usar una atri! de eleentos int. /uede incluir una #unción @ue re6ele el ob8eti6o con el nobre islagged4 ara ocultar los n;eros. *l resultado es una nue6a 6ersión de la #unción: ublic List]Cell^ getlaggedCells4 _`Ob List]Cell^ #laggedCells X ne? (rra5List]Cell^4 #or Cell cell : gae)oard4
i# cell.islagged44 #laggedCells.addce4 return #laggedCells _`Od Con estos sencillos cabios de nobre, es #=cil saber @ué sucede. *s la 6enta8a de seleccionar nobres adecuados.
#+itar la desinformación Los rograadores deben e6itar de8ar istas #alsas @ue di#iculten el signi#icado del código. -ebeos e6itar alabras cu5o signi#icado se ale8e del @ue retendeos. /or e8elo, %, ai> 5 sco son nobres de 6ariables obres 5a @ue son los nobres de lata#oras o 6ariantes de ni>. (un@ue se trate tra te del código de una %iotenusa 5 % are!ca la abre6iatura correcta, uede no serlo. Bo %aga re#erencia a un gruo de cuentas coo accountList a enos @ue realente sea una lista List4. La alabra lista tiene un signi#icado concreto ara los rograadores. i el contenedor de las cuentas no es realente una lista, uede ro6ocar #alsas conclusionesNU. /or tanto, resulta =s adecuado usar accountGrou, bunc%<#(ccounts o sileente accounts. *6ite usar nobres con 6ariaciones ínias. HCu=nto se tarda en areciar la sutil di#erencia entre +EDControlleror*##icientandling<#trings 5 +EDControlleror*##icienttorage<#trings en un óduloI (bas alabras tienen una #ora siilar. La ortogra#ía siilar de concetos arecidos es in#oración el uso de ortogra#ía inco%erente es desin#oración. *n los entornos odernos de Ja6a, el código se coleta de #ora auto=tica. *scribios 6arios caracteres de un nobre 5 ulsaos 6arias teclas ara obtener una lista de osibles ociones de un nobre. *s u5 ;til si los nobres de eleentos siilares se ordenan al#abéticaente de #ora con8unta 5 si las di#erencias son u5 e6identes, 5a @ue es robable @ue el rograador eli8a un ob8eto or nobre sin #i8arse en los coentarios o la lista de étodos roorcionados or una clase. n e8elo de nobre desin#orati6o sería el uso de la L in;scula o la < a5;scula coo nobres de 6ariables, sobre todo cobinados. *l roblea, e6identeente, es @ue se arecen a las constantes 5 0 resecti6aente: int a X l i# < XX l 4 a X < else l X 0 *l lector uede ensar @ue es una in6ención, ero %eos 6isto código con abundancia de estos eleentos. *n un caso, el autor del código, sugirió usar una #uente distinta ara @ue las di#erencias #ueran =s e6identes, una solución @ue se %ubiera transitido a todos los #uturos rograadores coo tradición oral o en un docuento escrito. *l roblea se resol6ió con car=cter de#initi6o 5 sin necesidad de crear nue6os roductos, con tan sólo cabiar los nobres. nobres .
4ealizar distinciones con sentido
Los rograadores se crean un roblea al crear código ;nicaente dirigido a un coilador o intérrete. /or e8elo, coo se uede usar el iso nobre ara %acer re#erencia a dos eleentos distintos en el iso =bito, uede 6erse tentado a cabiar un nobre de #ora arbitraria. *n ocasiones se %ace escribiéndolo incorrectaente, lo @ue ro6oca @ue los errores ortogr=#icos iidan la coilaciónOU. Bo basta con a3adir series de n;eros o alabras adicionales, aun@ue eso satis#aga al coilador. i los nobres tienen @ue ser distintos, tabién deben tener un signi#icado di#erente. Los nobres de series nuéricas a, a2Y aB4 son lo contrario a los nobres intencionados. Bo desin#oran, sileente no o#recen in#oración son una ista sobre la intención del autor. í8ese en lo siguiente: ublic static 6oid co5C%arsc%ar aU, c%ar a2U4 _`Ob #or int i X 0 i ] a.lengt% iZZ4 _`Ob a2iU X aiU _`Od _`Od *sta #unción se lee e8or cuando se usa source 5 destination coo nobres de arguentos. Las alabras adicionales son otra distinción sin sentido. "agine @ue tiene la clase /roduct. i tiene otra clase con el nobre /roduct"n#o o /roduct-ata, %abr= creado nobres distintos, ero con el iso signi#icado. "n#o 5 -ata son alabras adicionales, coo a, an 5 t%e. Bo es incorrecto usar re#i8os coo a 5 t%e ientras la distinción tenga sentido. "agine @ue usa a ara 6ariables locales 5 #or ara arguentos de #uncionesAU. *l roblea aarece cuando decide in6ocar la 6ariable t%eDor& or@ue 5a tiene otra 6ariable con el nobre !or&. Las alabras adicionales son redundantes. La alabra 6ariable no debe incluirse nunca en el nobre de una 6ariable. La alabra table no debe incluirse nunca en el nobre de una tabla. H*s e8or Baetring @ue BaeI H/odría ser Bae un n;ero de coa #lotanteI *n caso a#irati6o, incule la regla anterior sobre desin#oración. "agine @ue encuentra una clase con el nobre Custoer 5 otra con el nobre Custoeriste una alicación @ue lo ilustra. eos cabiado los nobres ara roteger al culable. eaos el error e>acto:
get(cti6e(ccount4 get(cti6e(ccounts4 get(cti6e(ccount"n#o4 HCóo saben los rograadores de este ro5ecto @ué #unción deben in6ocarI *n ausencia de con6enciones concretas, la 6ariable one5(ount no se distingue de one5, custoer"n#o no se distingue de custoer, account-ata no se distingue de account 5 t%eMessage no se distingue de essage. -ebe di#erenciar los nobres de #ora @ue el lector arecie las di#erencias.
8sar nombres 9ue se puedan pronunciar ( los %uanos se nos dan bien las alabras. Gran arte de nuestro cerebro se dedica al conceto de alabras. E, or de#inición, las alabras son ronunciables. ería una ena algastar esa arte de nuestro cerebro dedicada al lengua8e %ablado. /or tanto, cree nobres ronunciables. i no lo uede ronunciar, no odr= e>licarlo sin arecer tonto. *s un #actor iortante, 5a @ue la rograación es una acti6idad social. Cono!co una eresa @ue usa gen5d%s #ec%a de generación, a3o, es, día, %ora, inuto 5 segundo4 5 lo ronuncian tal cual. Eo tengo la costubre de ronunciar todo tal 5 coo lo 6eo escrito, de #ora @ue uc%os analistas 5 dise3adores acabaron or llaare algo coo Fgeniedees. *ra un c%iste 5 nos arecía di6ertido, ero en realidad est=baos tolerando el uso de nobres obres. Teníaos @ue e>licar las 6ariables a los nue6os rograadores 5 cuando las ronunciaban, usaban alabras in6entadas en lugar de nobres correctos. Coare: class -taRcrd02 _`Ob ri6ate -ate gen5d%s ri6ate -ate od5d%s ri6ate #inal tring s!@int X 02 QY Q _`Od con: class Custoer _`Ob ri6ate -ate generationTiesta ri6ate -ate odi#icationTiesta ri6ate #inal tring record"d X 02 QY Q _`Od (%ora se uede antener una con6ersación inteligente: F*%, Mi&e5, #í8ate en este registro. La arca de tieo de generación es ara a3ana. HCóo es osibleI
8sar nombres 9ue se puedan buscar Los nobres de una letra 5 las constantes nuéricas tienen un roblea: no son #=ciles de locali!ar en el te>to. e uede detectar M(+CL(*/*RT-*BT, ero el n;ero O resulta =s colicado. Las b;s@uedas ueden de6ol6er el dígito coo arte de nobres de arc%i6o, otras de#iniciones de constantes o e>resiones en las @ue se use con otra intención. Muc%o eor si la constante es un n;ero e>tenso 5 alguien %a
intercabiado los dígitos, lo @ue genera un error inediato 5 no aarece en la b;s@ueda. -el iso odo, el nobre e es una oción u5 obre ara 6ariables @ue el rograador tenga @ue buscar. buscar . *s la letra =s usada en inglés 5 aarece en la r=ctica totalidad de los te>tos de un rograa. ( este resecto, los nobres e>tensos sueran a los bre6es 5 cual@uier nobre @ue se s e ueda buscar suera a una un a constante en el código. /ersonalente re#iero nobres de una letra @ue sólo se uedan usar coo 6ariables locales dentro de étodos bre6es. 'a longit%d de %n nombre debe corresponderse al tamao de s% #mbito BU. i una 6ariable o constante se usa en 6arios untos del código, debe asignarle un nobre @ue se ueda buscar. Coare: #or int 8X0 8]WV 8ZZ4 _`Ob s ZX t8UV4Q _`Od con: int real-a5s/er"deal-a5 X V const int 7tensa, ero corobar= @ue resulta uc%o =s #=cil buscar 7
#+itar codificaciones Ea teneos su#icientes codi#icaciones coo ara tener @ue a3adir otras nue6as. (l codi#icar in#oración de tios o =bitos en un nobre se di#iculta la descodi#icación. Bo arece ra!onable @ue todos los nue6os nu e6os eleados tengan @ue arender otro lengua8e de codi#icación ade=s del código con el @ue 6an a traba8ar. *s una carga ental innecesaria a la %ora de intentar solucionar un roblea. Los nobres codi#icados resultan ironunciables 5 suelen escribirse de #ora incorrecta.
Botación /ngara (ntiguaente, cuando traba8=baos con lengua8es en los @ue la longitud de los nobres era un reto, inculíaos esta regla a nuestro esar. ortran #or!aba las codi#icaciones con6irtiendo la riera letra de un tio en código. *n sus rieras 6ersiones, )("C sólo se eritía una letra 5 un dígito. La notación %;ngara B4 lo lle6ó a un nue6o ni6el. B se consideraba u5 iortante en el (/" C de 7indo?s, donde todo era un control entero, un untero long, un untero 6oid o una de 6arias ileentaciones de string con di#erentes usos 5 atributos4. /or a@uel entonces, el coilador no corobaba los tios, de odo @ue los rograadores tean @ue recordarlos.
*n los lengua8es odernos disoneos de sisteas de tios =s coletos 5 los coiladores recuerdan los tios 5 los alican. *s =s, e>iste una tendencia a usar clases 5 #unciones =s bre6es ara @ue los usuarios arecien la declaración de las 6ariables @ue usan. Los rograadores de Ja6a no tienen @ue codi#icar tios. Los ob8etos son de tios #uertes 5 los entornos de edición %an a6an!ado tanto @ue detectan un error de tio antes de e8ecutar la coilación. /or ello, en la actualidad B 5 otras #oras de codi#icación de tios no son =s @ue un iediento. acen @ue sea =s colicado cabiar el nobre o el tio de una 6ariable o clase. -i#icultan la legibilidad del código 5 ueden %acer @ue el sistea de codi#icación con#unda al lector: /%oneBuber %onetring QQ el nobre no cabia cuando cabia el tio
Prefi)os de miembros Taoco es necesario a3adir coo re#i8o a los nobres de 6ariables. Las clases 5 #unciones tienen el taa3o necesario ara no tener @ue %acerlo, 5 debe usar un entorno de edición @ue resalte o coloree los iebros ara distinguirlos. ublic class /art _`Ob ri6ate tring dsc QQ La descrición te>tual 6oid setBaetring nae4 _`Ob dsc X nae _`Od _`Od ublic class /art _`Ob tring descrition 6oid set-escritiontring descrition4 _`Ob t%is.descrition X descrition _`Od _`Od (de=s, los usuarios arenden r=idaente a ignorar el re#i8o o su#i8o4 5 #i8arse en la arte con sentido del nobre. Cuanto =s código leeos, enos nos #i8aos en los re#i8os. *n ;ltia instancia, los re#i8os son un indicio de código antiguo.
Interfaces e Implementaciones *>iste un caso esecial ara usar codi#icaciones. "agine or e8elo @ue crea una #actoría abstracta ara crear #oras. \sta #actoría ser= una inter#a! 5 se ileentar= or edio de una clase concreta. HKué nobres debe asignarI H"%aeactor5 5 %aeactor5I /re#iero las inter#aces sin adornos. La " inicial, tan %abitual en los arc%i6os de legado actuales es, en el e8or de los casos, una distracción, 5 en el eor, un e>ceso de in#oración. Bo @uiero @ue is usuarios sean @ue se trata de una inter#a!, solaente @ue se trata de %aeactor5. i tengo @ue codi#icar la inter#a! o la ileentación, oto or ésta ;ltia. *s e8or usar %aeactor5" o incluso C%aeactor5, @ue codi#icar la inter#a!.
#+itar asignaciones mentales Los lectores no tienen @ue traducir entalente sus nobres en otros @ue 5a conocen. *ste roblea suele aarecer al elegir entre no usar térinos de doinio de robleas o de soluciones. *s un roblea de los nobres de 6ariables de una sola letra. n contador de bucles se odría bauti!ar coo i, 8 o & ero nunca l4 si su =bito es u5 reducido 5 no %a5 con#lictos con otros nobres, 5a @ue los nobres de una letra son tradicionales en contadores de bucles. in ebargo, en otros conte>tos, un nobre de una letra es una oción u5 obre: es coo un arcador de osición @ue el lector debe asignar entalente a un conceto real. Bo %a5 eor oti6o ara usar el nobre c @ue a 5 b 5a estén seleccionados. /or lo general, los rograadores son gente inteligente. ( la gente inteligente le gusta resuir de sus %abilidades entales. i uede recordar @ue r es la 6ersión en in;scula de una RL sin el %ost 5 el sistea, debe ser u5 listo. na di#erencia entre un rograador inteligente 5 un rograador ro#esional es @ue este ;ltio sabe @ue la claridad es lo *%e importa. Los ro#esionales usan sus oderes ara %acer el bien 5 crean código cód igo @ue otros uedan entender.
Bombres de clases Las clases 5 los ob8etos deben tener nobres o #rases de nobre coo Custoer, 7i&i/age, (ccount 5 (ddress/arser. *6ite alabras coo Manager, /rocessor, -ata, o "n#o en el nobre de una clase. *l nobre de una clase no debe ser un 6erbo.
Bombres de mDtodos Los étodos deben tener nobres de 6erbo coo ost/a5ent, delete/age o sa6e. Los étodos de acceso, de odi#icación 5 los redicados deben tener coo nobre su 6alor 5 usar coo re#i8o get, set e is de acuerdo al est=ndar de 8a6abean9U. string nae X elo5ee.getBae4 custoer.setBaei&e4 i# a5c%ec&.is/osted44Y (l sobrecargar constructores, use étodos de #actoría est=ticos con nobres @ue describan los arguentos. /or e8elo: Cole> #ulcru/oint X Cole>.roRealBuber2W.04 es e8or @ue: Cole> #ulcru/oint X ne? Cole>2W.04 Re#uerce su uso con6irtiendo en ri6ados sus constructores corresondientes.
Bo se eEceda con el atracti+o
i los nobres son deasiado inteligentes, sólo los recordar=n los @ue coartan el sentido del %uor de su autor, 5 sólo ientras se acuerden del c%iste. Habr=n @ué signi#ica la #unción ol5andGrenadeI in duda es atracti6a, ero en este caso uede @ue -elete"tes #uera =s indicado. <te or la claridad antes @ue or el entreteniiento. *n el código, el atracti6o suele aarecer coo #oras colo@uiales o 8ergas. /or e8elo, no use ?%ac&4 en lugar de &ill4. Bo recurra a broas culturales coo eatM5%orts4 si @uiere decir abort4. -iga lo @ue iense. /iense lo @ue diga.
8na palabra por concepto *li8a una alabra or cada conceto abstracto 5 anténgala. /or e8elo, resulta con#uso usar #etc%, retrie6e 5 get coo étodos e@ui6alentes de clases distintas. HCóo 6a a recordar @ué étodo se corresonde a cada claseI -esa#ortunadaente, tendr= @ue recordar @ué eresa, gruo o indi6iduo %a creado la biblioteca o clase en cuestión ara recordar @ué térino se %a eleado. *n caso contrario, erder= uc%o tieo buscando en encabe!ados 5 #ragentos de código. Los entornos de edición odernos coo *clise e "ntelliJ o#recen istas sensibles al conte>to, coo la lista de étodos @ue uede in6ocar en un deterinado ob8eto. /ero esta lista no suele incluir los coentarios de nobres de #unciones 5 listas de ar=etros. Tendr= suerte si uestra los nobres de ar=etros de las declaraciones de #unciones. Los nobres de #unciones deben ser indeendientes 5 co%erentes ara @ue ueda elegir el étodo correcto sin necesidad de b;s@uedas adicionales. -el iso odo, resulta con#uso tener un controlador, un adinistrador 5 un control en la isa base de código. HCu=l es la di#erencia entre -e6iceManager 5 /rotocolControllerI H/or @ué no son los dos controladores o adinistradoresI Hon controladoresI *l nobre %ace @ue esere @ue dos ob8etos tengan un tio di#erente 5 clases di#erentes. n lé>ico co%erente es una gran 6enta8a ara los rograadores @ue tengan @ue usar su código.
Bo /aga )uegos de palabras *6ite usar la isa alabra con dos #ines distintos. uele %acerse en 8uegos de alabras. i alica la regla de una alabra or o r concetos, acabar= con uc%as clases @ue or e8elo tengan un étodo add. Mientras las listas de ar=etros ar=e tros 5 los 6alores de6ueltos de los distintos étodos add sean se=nticaente e@ui6alentes, no %a5 roblea. in ebargo, alguien uede decidir usar la alabra add or oti6os de co%erencia, aun@ue no sea en el iso sentido. "agine @ue %a5 6arias clases en las @ue add crea un nue6o 6alor suando o concatenando dos 6alores e>istentes. "agine a%ora @ue crea una nue6a clase con un étodo @ue a3ada su ar=etro a una colección. H*ste étodo debe tener el étodo addI /arece co%erente 5a @ue %a5 otros uc%os étodos add, ero en este caso %a5 una di#erencia se=ntica, de odo @ue debeos usar un nobre coo insert o aend. Llaar add al nue6o étodo sería un 8uego de alabras. Buestro ob8eti6o, coo autores, es #acilitar la corensión del código. Kuereos @ue el código sea algo r=ido, no un estudio e>%austi6o. Kuereos usar un odelo en el @ue el autor sea el resonsable de transitir el signi#icado, no un odelo acadéico @ue e>i8a in6estigar el signi#icado ostrado.
8sar nombres de dominios de soluciones Recuerde @ue los lectores de su código ser=n rograadores. /or ello, use térinos in#or=ticos, algoritos, nobres de atrones, térinos ate=ticos 5 de=s. Bo con6iene e>traer todos los nobres del doinio de robleas 5a @ue no @uereos @ue nuestros colegas tengan @ue reguntar el signi#icado de cada nobre en esecial cuando 5a conocen el conceto ba8o otro nobre di#erente. *l nobre (ccountisitor tiene uc%o signi#icado ara un rograador #ailiari!ado con el atrón ""T
8sar nombres de dominios de problemas Cuando no e>ista un térino de rograación ara lo @ue esté %aciendo, use el nobre del doinio de robleas. (l enos el rograador @ue antenga su código odr= reguntar el signi#icado a un e>erto en doinios. earar los concetos de doinio de soluciones 5 de robleas es arte del traba8o de un buen rograador 5 dise3ador. *l código @ue tenga =s relación con los concetos del doinio de robleas tendr= nobres e>traídos de dic%o doinio.
A%adir conteEto con sentido (lgunos nobres tienen signi#icado or sí isos, ero la a5oría no. /or ello, debe incluirlos en un conte>to, en clases, #unciones 5 esacios de nobres con nobres
adecuados. Cuando todo lo de=s #alle, ueden usarse re#i8os coo ;ltio recurso. "agine @ue tiene las 6ariables #irstBae, lastBae, street, %ouseBuber, cit5, state 5 !icode. i las cobina, es e6idente @ue #oran una dirección. /ero si la 6ariable state se usa de #ora aislada en un étodo, Hsabría @ue #ora arte de una direcciónI /uede a3adir conte>to or edio de re#i8os: addrirstBae, addrLastBae, addrtate, etc. (l enos los lectores corender=n @ue estas 6ariables #oran arte de una estructura a5or. *6identeente, es e8or crear la clase (ddress. -e ese odo, incluso el coilador sabr= @ue las 6ariables ertenecen a un conceto =s alio. í8ese en el étodo del Listado 21. HLas 6ariables necesitan un conte>to con =s sentidoI *l nobre de la #unción sólo o#rece arte del conte>to, el resto se obtiene del algorito. Tras leerla #unción, 6er= @ue las tres 6ariables nuber, 6erb 5 luralModi#ier #oran arte del ensa8e guess statistics. -esa#ortunadaente, es necesario in#erir el conte>to. (l leer el étodo, el signi#icado de las 6ariables no es e6idente. !istado F ariables en un conte>to abiguo. ri6ate 6oid rintGuesstatisticsc%ar candidate, int count4 _`Ob tring nuber tring 6erb tring luralModi#ier i# count XX 04 _`Ob nuber X no 6erb X are luralModi#ier X s _`Od else i# count XX 4 _`Ob nuber X 6erb X is luralModi#ier X _`Od else _`Ob nuber X "nteger.totringcount4 6erb X are luralModi#ier X s _`Od tring guessMessage X tring.#orat T%ere s s ss, 6erb, nuber, candidate, luralModi#ier 4 rintguessMessage4 _`Od La #unción es deasiado e>tensa 5 las 6ariables aarecen or todas artes. /ara di6idir la #unción en #ragentos =s reducidos necesitaos crear una clase GuesstatisticsMessage 5 con6ertir a las tres 6ariables en caos de la isa. -e este odo contaos con un conte>to =s ob6io ara las tres 6ariables. oran arte sin duda de GuesstatisticsMessage. La e8ora del conte>to tabién erite @ue el algorito sea =s liio 5 se di6ida en #unciones =s reducidas 6éase el Listado 2124. !istado F ariables con un conte>to.
ublic class GuesstatisticsMessage ri6ate tring nuber ri6ate tring 6erb ri6ate tring luralModi#ier ublic tring a&ec%ar candidate, int count4 _`Ob create/lural-eendentMessage/artscount4 return tring.#orat T%ere s s ss, 6erb, nuber, candidate, luralModi#ier4 _`Od ri6ate 6oid create/lural-eendentMessage/artsint count4 _`Ob i# count XX 04 _`Ob t%ere(reBoLetters4 _`Od else i# cout XX 4 _`Ob t%ere"s
Bo a%adir conteEtos innecesarios *n la alicación iaginaria Gas tation -elu>e, no es aconse8able usar el re#i8o G- en todas las clases. *s traba8ar contra las %erraientas roorcionadas. "ntrodu!ca G 5 ulse la tecla de #inali!ación ara acceder a una u na lista interinable de todas las clases del sistea. H*s lo correctoI H/or @ué di#icultar la a5uda del "-*I -el iso odo, iagine @ue %a creado la clase Mailing(ddress en un ódulo de contabilidad de G-, con el nobre G-(ccount(ddress. -esués, necesita una dirección de correo ara la alicación de contacto con el cliente. Hsar= G-(ccount(ddressI HLe arece el nobre correctoI 0 de d e los O caracteres son redundantes redun dantes o irrele6antes.
Los nobres bre6es suelen ser =s adecuados @ue los e>tensos, siere @ue sean claros. Bo a3ada =s conte>to del necesario a un nobre. Los nobres account(ddress 5 custoer(ddress son er#ectos ara instancias de la clase (ddress ero no sir6en coo nobres de clase. (ddress sir6e coo nobre de clase. /ara distinguir entre direcciones M(C, direcciones de uertos 5 direcciones 7eb, odría usar /ostal(ddress, M(C 5 R". Los nobres resultantes son =s recisos, el ob8eti6o de cual@uier nobre.
Conclusión Lo =s colicado a la %ora de elegir un buen nobre es @ue re@uiere %abilidad descriti6a 5 acer6o cultural. *s un roblea de #oración =s @ue técnico, eresarial o adinistrati6o. Coo resultado, uc%a gente del sector no arende a %acerlo bien. La gente tee @ue al cabiar los nobres otros rograadores se @ue8en. Bosotros no coartios ese teor 5 agradeceos los cabios de nobre siere @ue sean a e8or4. *n uc%os casos no eori!aos los nobres de clases 5 étodos. saos %erraientas odernas ara estos detalles 5 así oder centraos en si el código se lee coo #rases o =rra#os, o al enos coo tablas 5 estructuras de datos una #rase no siere es la e8or #ora de ostrar datos4. eguraente acabar= sorrendiendo a alguien cuando cabie los nobres, coo uede suceder con cual@uier otra e8ora del código. Bo de8e @ue le detenga. (li@ue estas reglas 5 coruebe si e8ora o no la legibilidad de su código. i es el encargado de antener código de terceros, use %erraientas ara solucionar estos robleas.
G $unciones
*n los inicios de la rograación, cre=baos sisteas a artir de rutinas 5 subrutinas. -esués, en la éoca de ortran 5 /LQ, cre=baos nuestros sisteas con rograas, subrograas 5 #unciones. *n la actualidad, sólo las #unciones %an % an sobre6i6ido. on la riera línea organi!ati6a en cual@uier rograa. *n este caítulo 6ereos cóo crearlas. í8ese en el código del Listado W1. *s colicado encontrar una #unción e>tensa en itBesse0U, ero acabé encontrando ésta. Bo sólo es e>tensa, sino @ue tabién contiene código dulicado, uc%as cadenas 5 tios de datos e>tra3os, ade=s de (/" oco %abituales 5 nada e6identes. "ntente corenderlo en los ró>ios tres inutos. !istado GF
tltil.8a6a itBesse 200O0N94. ublic static tring testabletl _`Ob /age-ata age-ata, boolean includeuiteetu _`Od t%ro?s *>cetion _`Ob 7i&i/age ?i&i/age X age-ata.get7i&i/age 4 tring)u##er bu##er X ne? tring)u##er4 i# age-ata.%as(ttributeTest44 _`Ob i# includeuiteetu4 _`Ob 7i&i/age suiteetu X /ageCra?ler"l.get"n%erited/age uiteResonder."T**T/B(M*, ?i&i/age 4 i# suiteetu X null4 _`Ob 7i&i/age/at% age/at% X suiteetu.get/ageCra?ler4.getull/at% suiteetu4 tring age/at%Bae X /at%/arser.renderage/at%4 /at%/arser.renderage/at%4 bu##er.aendinclude 1setu .4 .aendage/at%Bae4 .aend_n4 _`Od _`Od 7i&i/age setu X /ageCra?ler"l.get"n%erited/ageet, ?i&i/age4 i# setu X null4 _`Ob 7i&i/age/at% setu/at% X ?i&i/age.get/ageCra?ler4.getull/at%setu4 tring setu/at%Bae X /at%/arser.rendersetu/at%4 bu##er.aendinclude 1setu .4 .aendsetu/at%Bae4 .aend_n4 _`Od _`Od bu##er.aendage-ata.getContent 44 i# age-ata.%as(ttributeTest44 _`Ob 7i&i/age teardo?n X /ageCra?ler"l.get"n%erited/ageTear-o?n, ?i&i/age4 i# teardo?n X null4 _`Ob 7i&i/age/at% tear-o?n/at% X ?i&i/age.get/ageCra?ler4.getull/at%teardo?n4 tring tear-o?n/at%Bae X /at%/arser.rendertear-o?n/ /at%/arser.rendertear-o?n/at%4 at%4 bu##er.aend_n4 .aendinclude 1teardo?n .4 .aendtear-o?n/at%Bae4 .aend_n4 _`Od
i# includeuiteetu4 _`Ob 7i&i/age suiteTeardo?n X /ageCra?ler"l.get"n%erited/age uiteResonder."T*T*(R-<7BB(M*, ?i&i/age 4 i# suiteTeardo?n X null4 _`Ob 7i&i/age/at% age/at% X suiteTeardo?n.get/ageCra?ler4.getull/at% suiteTeardo?n4 tring age/at%Bae X /at%/arser.renderage/at%4 /at%/arser.renderage/at%4 bu##er.aendinclude 1teardo?n .4 .aendage/at%Bae4 .aend_n4 _`Od _`Od _`Od age-ata.setContentbu##er.totring 44 return age-ata.gettl4 _`Od HTras tres inutos entiende la #unciónI eguraente no. /asan deasiadas cosas 5 %a5 deasiados ni6eles de abstracción di#erentes. a5 cadenas e>tra3as e in6ocaciones de #unciones e!cladas en instrucciones i# dobleente anidadas controladas or indicadores. in ebargo, con sencillas e>tracciones de código, alg;n cabio de nobres 5 cierta reestructuración, ude caturar la intención de la #unción en las nue6e líneas del Listado W1 2. Coruebe si a%ora la entiende. !istado GF tltil.8a6a re#actori!ación4. ublic static tring render/age7it%etus(ndTeardo?ns /age-ata age-ata, boolean isuite 4 t%ro?s *>cetion _`Ob boolean isTest/age X age-ata.%as(ttribute Test4 i# isTest/age4 _`Ob 7i&i/age test/age X age-ata.get7i&i/age4 tring)u##er ne?/ageContent X ne? tring)u##er4 includeetu/ages test/age, ne?/ageContent, isuite4 ne?/ageContent.aendage-ata.getContent44 "ncludeTeardo?n/agestest/age, ne?/ageContent, isuite4 age-ata.setContentne?/ageContent.totring44 _`Od return age-ata.gettl4 _`Od ( enos @ue sea un aluno de itBesse, seguraente no entienda los detalles. *ntender= @ue la #unción se encarga de a3adir =ginas de con#iguración 5 detalles en una =gina de rueba, @ue desués des ués uestra en TML. i est= #ailiari!ado con JnitU, 6er= @ue esta #unción ertenece a alg;n tio de estructura de ruebas basada en la 7eb 5, e6identeente, es correcto. Resulta sencillo adi6inar esta in#oración del Listado W12 ero
no del Listado W1. HKué tiene la #unción del Listado W12 ara @ue resulte sencilla de leer 5 entenderI HKué %a5 @ue %acer ara @ue una #unción transita su intenciónI HKué atributos odeos asignar a nuestras #unciones # unciones ara @ue el lector ueda intuir el tio de rograa rogr aa al @ue ertenecenI
3ama%o reducido La riera regla de las #unciones es @ue deben ser de taa3o reducido. La segunda es @ue deben ser todav+a m#s red%cidas. Bo es una a#iración @ue ueda 8usti#icar. Bo uedo ostrar re#erencias a estudios @ue deuestren @ue las #unciones u5 reducidas sean e8ores. Lo @ue sí uedo a#irar es @ue durante casi cuatro décadas %e creado #unciones de di#erentes taa3os. e creado onstruos de casi W000 líneas 5 otras uc%as #unciones de entre 00 5 W00 líneas. Tabién %e creado #unciones de 20 a W0 líneas de longitud. *sta e>eriencia e %a deostrado, ediante ensa5o 5 error, @ue las #unciones deben ser u5 reducidas. *n la década de 9A0 se decía @ue una #unción no debía suerar el taa3o de una antalla. /or a@uel entonces, las antallas T00 tenían 2V líneas or A0 colunas, 5 nuestros editores usaban V líneas ara tareas adinistrati6as. *n la actualidad, con una #uente ínia 5 un onitor de gran taa3o, se ueden enca8ar 0 caracteres or línea 5 00 líneas o =s en una antalla. Las líneas no deben tener 0 caracteres. Las #unciones no deben tener 00 líneas de longitud. Las #unciones deben tener una longitud aro>iada de 20 líneas. HKué taa3o ínio debe tener una #unciónI *n 999 6isité a $ent )ec& en su casa de
tltil.8a6a nue6a re#actori!ación4. ublic static tring render/age7it%etus(ndTeardo?ns /age-ata age-ata, boolean isuite4 t%ro?s *>cetion i# isTest/ageage-ata44 includeetu(ndTeardo?n/agesage-ata, isuite4 return age-ata.gettl4 _`Od
(lo9ues - sangrado *sto ilica @ue los blo@ues en instrucciones i#, else, ?%ile 5 siilares deben tener una línea de longitud @ue, seguraente, sea la in6ocación de una #unción. -e esta #ora, no sólo se reduce el taa3o de la #unción, sino @ue tabién se a3ade 6alor docuental 5a @ue la #unción in6ocada desde el blo@ue uede tener un nobre descriti6o. Tabién ilica @ue las #unciones no deben tener un taa3o e>cesi6o @ue albergue estructuras anidadas. /or tanto, el ni6el de sangrado de una #unción no debe ser a5or de uno o dos. *6identeente, de esta #ora las #unciones son =s #=ciles de leer 5 entender.
"acer una cosa
*s e6idente @ue el Listado W1 %ace =s de una cosa. Crea b;#eres, obtiene =ginas, busca =ginas %eredadas, a3ade a3 ade cadenas antiguas 5 genera TML. *l Listado W1 est= u5 ocuado reali!ando 6arias tareas. /or su arte, el Listado W1W sólo %ace una cosa: inclu5e con#iguraciones 5 detalles en =ginas de rueba. *l siguiente conse8o lle6a 6igente, de una u otra #ora, durante =s de W0 a3os: LAS '()C%O)!S S*LO D!!) ,AC!- ()A COSA. D!!) ,AC!-LO %!) / D!! S!- LO 0)%CO 1(! ,A2A). *l roblea de esta a#iración es saber @ué es una cosa. H*l Listado W1W %ace una cosaI e odría ensar @ue %ace tres: -eterinar si la =gina es una =gina de rueba. *n caso a#irati6o, incluir con#iguraciones 5 detalles. Reresentar la =gina en TML. HCu=l ser= de las tresI HLa #unción %ace una o tres cosasI Los tres asos de la #unción se encuentran un ni6el de abstracción or deba8o del nobre de la #unción. /odeos describir la #unción coo un bre6e =rra#o T< /(R(4WU: Para enderPageithSet%psAnd$eardowns, comprobamos si la p#gina es de pr%eba ., en caso afirmativo, incl%imos las config%raciones . los detalles" )n ambos casos, la representamos en ;$&'"
i una #unción sólo reali!a los asos situados un ni6el or deba8o del nobre de la #unción, entonces %ace una cosa. *n de#initi6a, creaos #unciones ara descooner concetos =s alios es decir, el nobre de la #unción4 en un con8unto de asos en el siguiente ni6el de abstracción. *s e6idente @ue el Listado W1 contiene asos en distintos ni6eles de abstracción, or lo @ue es ob6io @ue %ace =s de una cosa. "ncluso el Listado W12 tiene tres ni6eles de abstracción, coo %a deostrado la caacidad de reducirlo, ero sería colicado reducir con sentido el Listado W1W. /odríaos e>traer la instrucción i# en la #unción "ncludeetus(ndTeardo?ns"#Test/age, ero sólo reduciríaos el código sin cabiar el ni6el de abstracción. /or ello, otra #ora de saber @ue una #unción %ace =s de una cosa es e>traer otra #unción de la isa con un nobre @ue no sea una reducción de su ileentación GWVU.
Secciones en funciones í8ese en el Listado V1O. er= @ue la #unción generate/ries se di6ide en secciones coo declaraciones, iniciali!aciones 5 #iltros. *s un síntoa e6idente de @ue %ace =s de una cosa. Las #unciones @ue %acen una sola cosa no se ueden di6idir en secciones.
8n ni+el de abstracción por función /ara @ue las #unciones realicen Funa cosa, aseg;rese de @ue las instrucciones de la #unción se encuentran en el iso ni6el de abstracción. *l Listado W1 incule esta regla. "nclu5e concetos a un ele6ado ni6el de abstracción, coo gettl4 otros se encuentran en un ni6el interedio, coo tringage/at%Bae X /at%/arser.renderage/at%4 5 %a5 otros en un ni6el esecialente ba8o, coo .aend_n4. La e!cla de ni6eles de abstracción en una #unción siere resulta con#usa. Los lectores no sabr=n si una deterinada e>resión es un conceto esencial o un detalle. /eor toda6ía, si se e!clan detalles con concetos esenciales, auentar=n los detalles dentro de la #unción.
!eer código de arriba a aba)oH la regla descendente *l ob8eti6o es @ue el código se lea coo un te>to de arriba a aba8oVU. Kuereos @ue tras todas las #unciones aare!can las del siguiente ni6el de abstracción ara oder leer el rograa, descendiendo un ni6el n i6el de abstracción or 6e! ientras leeos la lista de #unciones. *s lo @ue denoino la regla descendente. /ara decirlo de otra #ora, @uereos leer el rograa coo si #uera un con8unto de =rra#os T<, en el @ue cada uno u no describe el ni6el actual de abstracción 5 %ace re#erencia r e#erencia a los =rra#os T< osteriores en el siguiente ni6el. Para incl%ir config%raciones . detalles, incl%imos config%raciones, desp%7s del contenido de la p#gina de pr%eba, . por 8ltimo los detalles" Para incl%ir las config%raciones, incl%imos la config%raci2n de s%ite si se trata de %na s%ite, . desp%7s la config%raci2n convencional" Para incl%ir la config%raci2n de s%ite1 b%scamos la 0erar*%+a principal de la
p#gina S%iteSetp . aadimos %na instr%cci2n incl%de con la r%ta de dicha p#gina" Para b%scar la 0erar*%+a principal
( los rograadores les resulta colicado arender esta regla 5 crear #unciones en un ;nico ni6el de abstracción, ero es un truco iortante. *s la cla6e ara reducir la longitud de las #unciones 5 garanti!ar @ue sólo %agan una cosa. (l conseguir @ue el código se lea de arriba a aba8o, se antiene la co%erencia de los ni6eles de abstracción. í8ese en el Listado W1O del #inal del caítulo. Muéstrala #unción testabletl odi#icada de acuerdo a estos rinciios. Cada #unción resenta a la siguiente 5 se antiene en un ni6el de abstracción co%erente.
Instrucciones Switc/ *s colicado usar una instrucción s?itc% de taa3o reducidoU. (un@ue sólo tenga dos casos, es a5or de lo @ue un blo@ue o #unción debería ser. Tabién es colicado crear una instrucción s?itc% @ue %aga una sola cosa. /or su naturale!a, las instrucciones s?itc% siere %acen B cosas. -esa#ortunadaente, no siere odeos e6itar las instrucciones s?itc% ero odeos aseguraos de incluirlas en una clase de ni6el in#erior 5 de no reetirlas. /ara ello, e6identeente, recurrios al olior#iso. í8ese en el Listado W1V. Muestra una de las oeraciones @ue ueden deender del tio de eleado. !istado GF
/a5roll.8a6a. ublic Mone5 calculate/a5*lo5ee e4 t%ro?s "n6alid*lo5eeT5e s?itc% e.t5e4 _`Ob case C
o deli6er/a5*lo5ee e, -ate date4, o uc%as otras, todas con la isa estructura. La solución al roblea 6éase el Listado W14 consiste en ocultar la instrucción s?itc% en una #actoría abstractaAU e iedir @ue nadie la 6ea. La #actoría usa la instrucción s?itc% ara crear las instancias adecuadas de los deri6ados de *lo5ee 5 las distintas #unciones, coo calculate/a5, is/a5da5 5 deli6er/a5, se entregar=n de #ora oliór#ica a tra6és de la inter#a! *lo5ee. !istado GF *lo5ee 5 actor5. ublic abstract class *lo5ee _`Ob ublic abstract boolean is/a5da54 ublic abstract Mone5 calculate/a54 ublic abstract 6oid deli6er/a5Mone5 a54 _`Od ublic inter#ace *lo5eeactor5 _`Ob ublic *lo5ee a&e*lo5ee*lo5eeRecord r4 t%ro?s "n6alid*lo5eeT5e _`Od ublic class *lo5eeactor5"l ileents *lo5eeactor5 _`Ob ublic *lo5ee a&e*lo5ee*lo5eeRecord r4 t%ro?s "n6alid*lo5eeT5e _`Ob s?itc% r.t5e4 _`Ob case C
8sar nombres descripti+os *n el Listado W1O, %eos cabiado el nobre de la #unción de e8elo de testabletl a etuTeardo?n"ncluder.render. *s un nobre =s aroiado 5a @ue describe e8or el coetido de la #unción. Tabién %eos asignado a los étodos ri6ados un nobre descriti6o coo isTestable o includeetu(ndTeardo?n/ages. Bo %a5 @ue
ol6idar el 6alor de los nobres correctos. Recuerde el rinciio de 7ard: Fabeos @ue traba8aos con código liio cuando cada rutina es =s o enos lo @ue eser=baos. /ara alcan!ar este rinciio, gran arte del es#uer!o se basa en seleccionar nobres adecuados ara e@ue3as #unciones @ue %acen una cosa. Cuanto =s reducida 5 concreta sea una #unción, =s sencillo ser= elegir un nobre descriti6o. Bo tea los nobres e>tensos. n nobre descriti6o e>tenso es uc%o e8or @ue uno bre6e ero enig=tico. se una con6ención de nobres @ue erita leer 6arias alabras en los nobres de las #unciones 5 use esas alabras ara asignar a la #unción un nobre @ue describa su coetido. Bo tea dedicar tieo a elegir un buen nobre. -e %ec%o, debería robar con 6arios nobres 5 leer el código con todos ellos. Los "-* odernos coo *clise o "ntelliJ #acilitan el cabio de nobres. se uno de estos "-* 5 e>eriente con di#erentes nobres %asta @ue encuentre uno @ue sea lo bastante descriti6o. La elección de nobres descriti6os clari#ica el dise3o de los ódulos 5 le erite e8orarlos. Bo es e>tra3o @ue la b;s@ueda de nobres adecuados genere una reestructuración #a6orable del código. ea co%erente con los nobres. se las isas #rases, sustanti6os 5 6erbos en los nobres de #unción @ue eli8a ara los ódulos. /ruebe, or e8elo, con includeetu(ndTeardo?n/ages, includeetu/ages, inc ludeetu/ages, includeuiteetu/age e includeetu/age. La estructura siilar de estos nobres erite @ue la secuencia cuente una %istoria. *n realidad, si 6e la secuencia anterior, seguraente se regunte @ué %a asado con includeTeardo?n/ages, includeuiteTeardo?n/age e includeTeardo?n/age.
Argumentos de funciones
*l n;ero ideal de arguentos ara una #unción es cero. -esués uno on=dico4 5 dos di=dico4. iere @ue sea osible, e6ite la resencia de tres arguentos tri=dico4. M=s de tres arguentos oli=dico4 re@uiere una 8usti#icación esecial 5 no es u5
%abitual. Los arguentos son cole8os 5a @ue re@uieren un gran oder concetual. /or ello suelo e6itarlos en los e8elos. í8ese en tring)u##er. /odríaos %aberlo asado coo arguento en lugar de coo 6ariable de instancia, ero los lectores %abrían tenido @ue interretarlo cada 6e! @ue lo 6ieran. (l leer la %istoria @ue cuenta el ódulo, includeetu/age4 es =s sencillo de interretar @ue includeetu/age"ntone?/ageContent4. *l arguento se encuentra en un ni6el de abstracción di#erente @ue el nobre de la #unción 5 nos obliga a conocer un detalle tring)u##er4 @ue no es esecialente iortante en ese oento. Los arguentos son toda6ía =s colicados desde un unto de 6ista de ruebas. "agine la di#icultad de crear todos los casos de rueba ara garanti!ar el #uncionaiento de las distintas cobinaciones de arguentos. i no %a5 arguentos, todo es =s sencillo. i %a5 uno, no es deasiado di#ícil. Con dos arguentos el roblea es =s cole8o. Con =s de dos arguentos, robar cada cobinación de 6alores adecuados es todo un reto. Los arguentos de salida son =s di#íciles de entender @ue los de entrada. (l leer una #unción, estaos acostubrados al conceto de in#oración a3adida a la #unción a tra6és de arguentos 5 e>traída a tra6és de un 6alor de6uelto. Bo eseraos @ue la in#oración se de6uel6a a tra6és de los arguentos. /or ello, los arguentos de salida suelen obligaos a reali!ar una corobación doble. n arguento de salida es la e8or oción, desués de la ausencia de arguentos. etuTeardo?nlncluder.renderage-ata4 se entiende bien. *6identeente, 6aos a reresentar los datos en el ob8eto age-ata.
$ormas monádicas /abituales a5 dos oti6os rinciales ara asar un solo arguento a una #unción. /uede @ue realice una regunta sobre el arguento, coo en boolean #ile*>istsM5ile4, o @ue rocese el arguento, lo trans#ore en otra cosa 5 lo de6uel6a. /or e8elo, "nuttrea #ile<enM5ile4 trans#ora un nobre de arc%i6o tring en un 6alor de6uelto "nuttrea. Los usuarios eseran estos dos usos cuando 6en una #unción. -ebe elegir nobres @ue realicen la distinción con claridad 5 usar siere abas #oras en un conte>to co%erente consulte el aartado sobre searación de consultas de coandos4. na #ora enos %abitual ero u5 ;til ara un arguento es un e6ento. *n esta #ora, %a5 arguento de entrada ero no de salida. *l rograa debe interretar la in6ocación de la #unción coo e6ento 5 usar el arguento ara alterar el estado del sistea, or e8elo, 6oid ass?ord(ttetailedBtiesint attets4. se esta #ora con recaución. -ebe ser claro ara ar a el lector @ue se trata de un e6ento. *li8a nobres 5 conte>tos con atención. "ntente e6itar #unciones on=dicas @ue no tengan estas #oras, or e8elo, 6oid includeetu/age"ntotring)u# #er ageTe>t4. *l uso de un arguento de salida en lugar de un 6alor de6uelto ara reali!ar trans#oraciones resulta con#uso. i una #unción 6a a trans#orar su arguento de entrada, la trans#oración debe aarecer coo 6alor de6uelto. in duda tring)u##ertrans#ortring)u##er in4 es e8or @ue 6oid trans#ortring)u##er out4, aun@ue la ileentación del rier caso de6uel6a solaente el arguento de entrada. (l enos se a8usta a la #ora de la trans#oración.
Argumentos de indicador Los arguentos de indicador son %orribles. /asar un 6alor )ooleano a una #unción es una r=ctica totalente desaconse8able. Colica inediataente la #ira del étodo e indica @ue la #unción %ace =s de una cosa. ace algo si el indicador es true 5 otra cosa di#erente si es #alse. *n el Listado W1O no se uede e6itar, or@ue los in6ocadores 5a asan el indicador 5 el ob8eti6o era liitar el =bito a la #unción 5 desués, ero la in6ocación de render true4 es con#usa ara el lector. i se desla!a el ratón sobre la in6ocación 6eos @ue render boolean isuite4 uede a5udar, ero no deasiado. Tendreos @ue di6idir la #unción en dos: renderoruite4 5 renderoringleTest4.
$unciones diádicas na #unción con dos arguentos es =s di#ícil de entender @ue una #unción on=dica. /or e8elo ?riteieldnae4 es =s #=cil de entender @ue ?riteield oututtrea, nae49U. (un@ue en abos casos el signi#icado es e6idente, la riera se cata e8or 6isualente. La segunda re@uiere una bre6e ausa %asta @ue ignoraos el segundo ar=etro, lo @ue en ;ltia instancia genera robleas 5a @ue no debeos ignorar esa arte del código. Las artes @ue ignoraos son las @ue esconden los errores. /ero en ocasiones se necesitan dos arguentos. /or e8elo. /oint X ne? /oint0,04 es totalente ra!onable. Los untos cartesianos suelen adotar dos arguentos. -e %ec%o, sería u5 sorrendente 6er /oint04. in ebargo, en este caso abos arguentos son coonentes ordenados de un iso 6alor, ientras @ue oututtrea 5 nae carecen de una co%esión o un orden natural. "ncluso #unciones di=dicas e6identes coo assert*@ualse>ected, actual4 resultan roble=ticas. HCu=ntas 6eces %a incluido el 6alor real r eal en su osición eseradaI Los dos arguentos carecen de un orden natural. *l orden real 5 eserado es una con6ención @ue se ad@uiere gracias a la r=ctica. Las cobinaciones di=dicas no son el al en ersona 5 tendr= @ue usarlas. in ebargo, recuerde @ue tienen un recio 5 @ue debe aro6ec%ar los ecanisos disonibles ara con6ertirlas en unitarias. /or e8elo, uede %acer @ue el étodo ?riteield sea un iebro de oututtrea ara oder usar oututtrea.?riteieldnae4, o odría con6ertir oututtrea en una 6ariable iebro de la clase actual ara no tener @ue asarla. "ncluso odría e>traer una u na nue6a clase coo ield7riter @ue usara oututtrea en su constructor 5 tu6iera un étodo ?rite.
3riadas Las #unciones @ue acetan tres arguentos son sin duda uc%o =s di#íciles de entender @ue las de dos. Los robleas a la %ora de ordenar, ignorar o detenerse en los arguentos se dulican. /iense atentaente antes de crear una triada. /or e8elo, #í8ese en la sobrecarga de assert*@uals @ue aceta tres arguentos: assert*@ualsessage, e>ected, actual4. HCu=ntas 6eces lee el ensa8e 5 iensa @ue es lo eseradoI e 6isto esta triada en concreto uc%as 6eces. -e %ec%o, siere @ue la 6eo,
tengo @ue reasarla antes de ignorar el ensa8e. /or otra arte, %a5 otra triada @ue no es tan negati6a: assert*@uals.0, aount, . 004. (un@ue tabién e>i8a doble atención, erece la ena. Con6iene recordar siere @ue la igualdad de los 6alores de coa #lotante es algo relati6o
Ob)eto de argumento Cuando una #unción arece necesitar dos o =s arguentos, es robable @ue alguno de ellos se inclu5a en una clase roia. í8ese en la di#erencia entre las dos siguientes declaraciones: Circle a&eCircle double >, double 5, double radius4 Circle a&eCircle/oint center, double radius4 La reducción del n;ero de arguentos ediante la creación de ob8etos uede arecer una traa ero no lo es. Cuando se asan gruos de 6ariables de #ora con8unta, coo > e 5 en el e8elo anterior, es robable @ue #oren arte de un conceto @ue se erece un nobre roio.
!istas de argumentos *n ocasiones tendreos @ue asar un n;ero 6ariable de arguentos a una #unción. í8ese en el étodo tring.#orat: tring.#orat s ?or&ed .2# %ours., nae, %ours4 i los arguentos 6ariables se rocesan de la isa #ora, coo en el e8elo anterior, ser=n e@ui6alentes a un ;nico arguento de tio List. /or tanto, tring.#orat es en realidad di=dico. -e %ec%o, la siguiente declaración de tring.#orat es claraente di=dica. ublic tring #orattring #orat.
Kerbos - palabras cla+e La selección de nobres correctos ara una #unción e8ora la e>licación de su coetido, así coo el orden 5 el coetido de los arguentos. *n #orato on=dico, la #unción 5 el arguento deben #orar un ar de 6erbo 5 sustanti6o. /or e8elo, ?ritenae4 resulta u5 e6ocador. ea lo @ue sea nae, sin duda se escribe ?rite4. n nobre =s acertado odría ser ?riteieldnae4, @ue nos dice @ue nae es un cao #ield4. \ste es un e8elo de alabra cla6e coo nobre de #unción. Con este #orato codi#icaos los nobres de los arguentos en el nobre de la #unción. /or e8elo, assert*@uals se odría %aber escrito coo assert*>ected*@uals (ctuale>ected, actual4, lo @ue itiga el roblea de tener @ue recordar el orden de los arguentos.
Sin efectos secundarios Los e#ectos secundarios son entiras. u #unción roete %acer una cosa, ero tabién %ace otras cosas ocultas. *n ocasiones reali!a cabios ineserados en las 6ariables de su roia clase. *n ocasiones las con6ierte en las 6ariables asadas a la #unción o a eleentos globales del sistea. *n cual@uier caso, se coete un enga3o @ue suele ro6ocar e>tra3as cobinaciones teorales 5 deendencias de orden. í8ese en la #unción del Listado W1N, aarenteente ino#ensi6a. sa un algorito est=ndar ara coarar userBae con ass?ord. -e6uel6e true si coinciden 5 #alse si %a5 alg;n roblea, ero tabién %a5 un e#ecto secundario. HLo detectaI !istado GFL
seralidator.8a6a. ublic class seralidator _`Ob ri6ate Cr5togra%er cr5togra%er ublic boolean c%ec&/ass?ordtring userBae, tring ass?ord4 _`Ob ser user X serGate?a5.#ind)5BaeuserBae4 i# user X ser.BLL4 _`Ob tring coded/%rase X user.get/%rase*ncoded)5/as user.get/%rase*ncoded)5/ass?ord4 s?ord4 tring %rase X cr5togra%er.decr5tcoded/% cr5togra%er.decr5tcoded/%rase, rase, ass?ord4 i# alid /ass?ord.e@uals%rase44_`Ob /ass?ord.e@uals%rase44 _`Ob ession.initiali!e4 return true _`Od _`Od return #alse _`Od _`Od *l e#ecto secundario es la in6ocación de ession.initiali!e4. La #unción c%ec&/ass?ord, or su nobre, a#ira corobar la contrase3a. *l nobre no ilica @ue inicialice la sesión. /or tanto, un in6ocador @ue se crea lo @ue dice el nobre de la #unción se arriesga a borrar los datos de sesión actuales cuando decida corobar la 6alide! del usuario. *ste e#ecto secundario genera una cobinación teoral. *s decir, sólo se uede in6ocar c%ec&/ass?ord en deterinados oentos cuando se ueda iniciali!ar la sesión4. i no se in6oca en orden, se ueden erder los datos de la sesión. Las cobinaciones teorales son con#usas, en esecial cuando se ocultan coo e#ecto secundario. i tiene @ue reali!ar una cobinación teoral, %=galo de #ora clara en el nobre de la #unción. *n este caso, odríaos cabiar el nobre de la #unción or c%ec&/ass?ord(nd"nitiali!eession, ero inculiría la nora de %acer una sola cosa.
Argumentos de salida Los arguentos suelen interretarse coo entradas de una #unción. i lle6a 6arios a3os rograando, esto5 seguro de @ue %abr= 6isto un arguento @ue en 6e! de ser de entrada era de salida. /or e8elo
aendooters4 H*st= #unción a3ade s al #inal de algoI H< a3ade el #inal de algo a sI Hs es una entrada o una salidaI Lo sabeos al 6er la #ira de la #unción: ublic 6oid aendootertring)u##er reort4 *sto lo aclara todo, ero ara ello %a5 @ue corobar la declaración de la #unción. Todo lo @ue le obligue a corobar la #ira de la #unción es un es#uer!o doble. *s una ausa cogniti6a 5 debe e6itarse. (ntes de la rograación orientada a ob8etos, era necesario tener arguentos de salida. in ebargo, gran arte de su necesidad desaarece en los lengua8es orientados a ob8etos, ensados ara actuar coo arguento de salida. *s decir, sería =s indicado in6ocar aendooter coo reort.aendooter4. /or lo general, los arguentos de salida deben e6itarse. i su #unción tiene @ue cabiar el estado de un eleento, %aga @ue cabie el estado de su ob8eto contenedor.
Separación de consultas de comando Las #unciones deben %acer algo o resonder a algo, ero no abas cosas. u #unción debe cabiar el estado de un ob8eto o de6ol6er in#oración sobre el iso, ero abas oeraciones causan con#usión. í8ese en la siguiente #unción: ublic boolean settring attribute, tring 6alue4 *sta #unción establece el 6alor de un atributo 5 de6uel6e true en caso de é>ito o #alse si el atributo no e>iste. *sto ro6oca la resencia de una e>tra3a instrucción coo la siguiente: i# setusernae, unclebob44Y "agínelo desde el unto de 6ista del lector. HKué signi#icaI H/regunta si el atributo Fusernae se %a establecido antes en Funclebob, o si el atributo Fusernae se %a establecido correctaente en FunclebobI *s colicado saberlo or la in6ocación 5a @ue no es e6idente si set es un 6erbo o un ad8eti6o. *l autor retendía @ue set #uera un 6erbo, ero el conte>to de la instrucción i# arece un ad8eti6o. La instrucción se lee coo Fsi el atributo usernae se %a establecido re6iaente en unclebob, no coo Festablecer el atributo usernae en unclebob 5 si #unciona, entoncesY. /odríaos solucionarlo si cabiaos el nobre de la #unción set or set(ndC%ec&"#*>ists, ero no e8oraría e8orar ía la legibilidad de la instrucción i#. La 6erdadera solución es searar el coando de la consulta ara e6itar la abigedad. i# attribute*>istsusernae44 _`Ob set(ttributeusernae, unclebob4 Y _`Od
Me)or eEcepciones 9ue de+ol+er códigos de error -e6ol6er códigos de error de #unciones de coando es un sutil inculiiento de la searación de coandos de consulta. ace @ue los coandos usados asciendan a e>resiones en los redicados de las instrucciones i#. i# delete/ageage4 XX *<$4 Bo adece la con#usión entre 6erbo 5 ad8eti6o, ero genera estructuras anidadas. (l
de6ol6er un código de error se crea un roblea: el in6ocador debe rocesar el error de #ora inediata. i# delete/ageage4 XX *<$4 _`Ob i# registr5.deleteRe#erenceage.nae4 XX *<$4 _`Ob i# con#ig$e5s.delete$e5age.nae.a&e$e544 XX *<$4 _`Ob logger.logage deleted4 _`Od else _`Ob logger.logcon#ig$e5 not deleted4 _`Od _`Od else _`Ob logger.logdeleteRe#erence #ro registr5 #ailed4 _`Od _`Od else _`Ob logger.logdelete #ailed4 return **RRceciones en lugar de códigos de error, el código de rocesaiento del error se uede searar del código de ruta 5 se uede u ede sili#icar: tr5 _`Ob delete/ageage4 registr5.deleteRe#erenceage.nae4 con#ig$e5s.delete$e5age.nae.a&e$e544 _`Od catc% *>cetion e4 _`Ob logger.loge.getMessage44 _`Od
#Etraer blo9ues 3r-Catc/ Los blo@ues tr5Qcatc% no son atracti6os or naturale!a. Con#unden la estructura del código 5 e!clan el rocesaiento de errores con el noral. /or ello, con6iene e>traer el cuero de los blo@ues tr5 5 catc% en #unciones indi6iduales. ublic 6oid delete/age age4 _`Ob tr5 _`Ob delete/age(nd(llRe#erencesage4 _`Od catc% *>cetion e4 _`Ob log*rrore4 _`Od _`Od ri6ate 6oid delete/age(nd(llRe#erences/age age4 t%ro?s *>cetion _`Ob delete/ageage4 registr5.deleteRe#erenceage.nae4 con#ig$e5s.delete$e5age.nae.a&e$e544 _`Od ri6ate 6oid log*rror*>cetion e4 _`Ob
logger.loge.getMessage44 _`Od *n este caso, la #unción delete es de rocesaiento de errores. *s #=cil de entender e ignorar. La #unción delete/age(nd(llRe#erences es ara los rocesos de borrar una =gina. *l rocesaiento de errores se uede ignorar. -e este odo, la searación #acilita la corensión 5 la odi#icación del código.
#l procesamiento de errores es una cosa Las #unciones sólo deben %acer una cosa 5 el rocesaiento de errores es un e8elo. /or tanto, una #unción @ue rocese errores no debe %acer nada =s. *sto ilica coo en el e8elo anterior4 @ue, si una #unción inclu5e la alabra cla6e tr5, debe ser la riera de la #unción 5 @ue no debe %aber nada =s desués de los blo@ues blo@u es catc%Q#inall5.
#l imán de dependencias #rror.)a+a La de6olución de códigos de error suele ilicar @ue e>iste una clase o enueración en la @ue se de#inen los códigos de error. ublic enu *rror _`Ob <$, "B(L"-, B<C, Lceciones en lugar de códigos de error, las nue6as e>ceciones son deri6aciones de la clase de la e>ceción. e ueden a3adir sin necesidad de 6ol6er a coilar o ileentar 2U.
Bo repetirse ;>
í8ese de nue6o en el Listado W1 6er= @ue %a5 un algorito @ue se reite cuatro 6eces, en los casos et, uiteet, Tear-o?n 5 uiteTear-o?n. Bo es #=cil detectar esta reetición 5a @ue las cuatro instancias se e!clan con otro código, ero la dulicación es un roblea 5a @ue auenta el taa3o del código 5 re@uerir= una odi#icación cu=drule si alguna 6e! cabia el algorito. Tabién se cuadrilica el riesgo de errores. *sta dulicación se reedia gracias al étodo include del Listado W1O. uel6a a leer el código 5 #í8ese en cóo se %a e8orado la legibilidad del código reduciendo la dulicación. La dulicación uede ser la raí! de todos los robleas del software. *>isten nuerosos rinciios 5 r=cticas ara controlarla o eliinarla. "agine @ue todas las #oras norales de la base de datos de Codd sir6ieran ara eliinar la dulicación de datos. "agine tabién cóo la rograación orientada a ob8etos concentra el código en clases base @ue en otros casos serian redundantes. La rograación estructurada, la rograación orientada a asecto 5 la orientada or ientada a coonentes son, en arte, estrategias ara eliinar dulicados. /arece @ue, desde des de la aarición de las subrutinas, las inno6aciones en desarrollo de software %an sido un intento continuado or eliinar la dulicación de nuestro código #uente.
Programación estructurada (lgunos rograadores siguen las reglas de rograación estructurada de *dsger -i8&stra2WU. -i8&stra a#ira @ue todas las #unciones 5 todos los blo@ues de una #unción deben tener una entrada 5 una salida. *stas reglas ilican @ue sólo debe %aber una instrucción return en una #unción, @ue no debe %aber instrucciones brea& o continue en un bucle 5 nunca, ba8o ning;n conceto, debe %aber instrucciones goto. (un@ue arecieos los ob8eti6os 5 discilinas de la rograación estructurada, no sir6en de uc%o cuando las #unciones son de reducido taa3o. u 6erdadero bene#icio se arecia en #unciones de gran taa3o. /or tanto, si sus #unciones son de taa3o reducido, una instrucción return, brea& o continue no %ar= da3o alguno 5 en ocasiones uede resultar =s e>resi6a @ue la regla de una entrada 5 una salida. /or otra arte, goto sólo tiene sentido en #unciones de gran
taa3o 5 debe e6itarse.
Cómo crear este tipo de funciones La creación de software es coo cual@uier otro roceso creati6o. (l escribir un in#ore o un artículo, riero se estructuran las ideas 5 desués el ensa8e %asta @ue se lea bien. *l rier borrador uede estar es tar desorgani!ado, de odo @ue lo retoca 5 e8ora %asta @ue se lea de la #ora adecuada. Cuando creo #unciones, suelen ser e>tensas 5 colicadas, con abundancia de sangrados 5 bucles anidados. Con e>tensas listas de arguentos, nobres arbitrarios 5 código dulicado, ero tabién cuento con una serie de ruebas de unidad @ue abarcan todas 5 cada una de las líneas de código. /or tanto, retoco el código, di6ido las #unciones, cabio los nobres 5 eliino los dulicados. Redu!co los étodos 5 los reordeno. *n ocasiones, eliino clases enteras, ientras antengo las ruebas. (l #inal, consigo #unciones @ue culen las reglas detalladas en este caítulo. Bo las escribo al coen!ar 5 dudo @ue nadie ueda %acerlo.
Conclusión Todo sistea se crea a artir de un lengua8e esecí#ico del doinio dise3ado or los rograadores ara describir des cribir dic%o sistea. Las #unciones son los 6erbos 6er bos del lengua8e 5 las clases los sustanti6os. Bo es 6ol6er a la noción de @ue los sustanti6os 5 6erbos de un docuento de re@uisitos son las clases 5 #unciones de un sistea. *s una 6erdad uc%o =s antigua. *l arte de la rograación es, 5 %a sido siere, el arte del dise3o del lengua8e. Los rograadores e>erientados iensan en los sisteas coo en %istorias @ue contar, no coo en rograas @ue escribir. Recurren a las restaciones del lengua8e de rograación seleccionado ara crear cr ear un lengua8e e>resi6o e8or 5 =s coleto co leto @ue oder usar ara contar esa es a %istoria. /arte de ese lengua8e es la 8erar@uía de #unciones @ue describen las acciones @ue se ueden reali!ar en el sistea. -ic%as acciones se crean ara usar el lengua8e de doinio concreto @ue de#inen ara contar su e@ue3a arte de la %istoria. *n este caítulo %eos 6isto la ec=nica de la creación de #unciones correctas. i alica estas reglas, sus #unciones ser=n bre6es, con nobres correctos, 5 bien organi!adas, ero no ol6ide @ue su 6erdadero ob8eti6o es contar la %istoria del sistea 5 @ue las #unciones @ue escriba deben enca8ar en un lengua8e claro 5 reciso @ue le sir6a ara contar esa %istoria.
Setup3eardownlncIuder !istado GF=
etuTeardo?n"ncluder.8a6a. ac&age #itnesse.%tl
iort #itnesse.resonders.run.uiteResonder #itnesse.resonders.run. uiteResonder iort #itnesse.?i&i. ublic class etuTeardo?nlncluder _`Ob ri6ate /age-ata age-ata ri6ate boolean isuite ri6ate 7i&i/age test/age ri6ate tring)u##er ne?/ageContent ri6ate /ageCra?ler ageCra?ler ublic static tring render/age-ata age-ata4 t%ro?s *>cetion _`Ob return renderage-ata, #alse4 _`Od ublic static tring render/age-ata age-ata, boolean isuite4 t%ro?s *>cetion _`Ob return ne? etuTeardo?n"ncluderage-ata4.r etuTeardo?n"ncluderage-ata4.renderisuite4 enderisuite4 _`Od ri6ate etuTeardo?n"ncluder/age-ata age-ata4 _`Ob t%is.age-ata X age-ata test/age X age-ata.get7i&i/age4 ageCra?ler X test/age.get/ageCra?ler4 ne?/ageContent X ne? tring)u##er4 _`Od ri6ate tring renderboolean isuite4 t%ro?s *>cetion _`Ob t%is.isuite X isuite i# isTest/age44 includeetu(ndTeardo?n/ages4 return age-ata.gettl4 _`Od ri6ate boolean isTest/age4 t%ro?s *>cetion _`Ob return age-ata.%as(ttributeTest4 _`Od ri6ate 6oid includeetu(ndTeardo?n/ages4 t%ro?s *>cetion _`Ob includeetu/ages4 include/ageContent4 includeTeardo?n/ages4 udate/ageContent4 _`Od ri6ate 6oid includeetu/ages4 t%ro?s *>cetion _`Ob i# isuite4 includeuiteetu/age4 includeetu/age4 _`Od ri6ate 6oid includeuiteetu/age4 t%ro?s *>cetion _`Ob includeuiteResonder."T**T/B(M*, 1setu4 _`Od ri6ate 6oid includeetu/age4 t%ro?s *>cetion _`Ob includeet, 1setu4 _`Od
ri6ate 6oid include/ageContent4 t%ro?s *>cetion _`Ob ne?/ageContent.aendage-ata.getContent44 _`Od ri6ate 6oid includeTeardo?n/ages4 t%ro?s *>cetion _`Ob includeTeardo?n/age4 i# isuite4 includeuiteTeardo?n/age4 _`Od ri6ate 6oid includeTeardo?n/age4 t%ro?s *>cetion _`Ob includeTear-o?n, 1teardo?n4 _`Od ri6ate 6oid includeuiteTeardo?n/age4 t%ro?s *>cetion _`Ob includeuiteResonder."T*T*(R-<7BB(M*, 1teardo?n4 _`Od ri6ate 6oid udate/ageContent4 t%ro?s *>cetion _`Ob age-ata.setContentne?/ageContent.totring44 _`Od ri6ate 6oid includetring ageBae, tring arg4 t%ro?s *>cetion 7i&i/age in%erited/age X #ind"n%erited/ageageBae4 i# in%erited/age X null4 _`Ob tring age/at%Bae X get/at%Baeor/agein%erited/age4 build"nclude-irecti6eage/at%Bae, arg4 _`Od _`Od ri6ate 7i&i/age #ind"n%erited/agetring ageBae4 t%ro?s *>cetion _`Ob return /ageCra?ler"l.get"n%erited/ageageBae, test/age4 _`Od ri6ate tring get/at%Baeor/age7i&i/age age4 t%ro?s *>cetion _`Ob 7i&i/age/at% age/at% X ageCra?ler.getull/at%age4 Return /at%/arser.renderage/at%4 /at%/arser.renderage/at%4 _`Od ri6ate 6oid build"nclude-irecti6etring age/at%Bae, tring arg4 _`Ob ne?/ageContent .aend_ninclude 4 .aendarg4 .aend .4 .aendage/at%Bae4 .aend_n4 _`Od _`Od
(ibliograf:a ;?P=N>: $ernig%an and /laug%er, $he )lements of Programming St.le, 2d. ed., McGra?1ill, 9OA. ;PPP<>: Robert C. Martin, (gile o#t?are -e6eloent: /rinciles, /atterns, and
/ractices, /rentice all, 2002. ;O$>: -esign /atterns: *leents o# Reusable : $he Pragmatic Programmer , (ndre? unt, -a6e T%oas, (ddison1 7esle5, 2000. ;SP=>: Str%ct%red Programming , <. J. -a%l, *. 7. -i8&stra, C. (. R. oare, (cadeic /ress, London, 9O2.
Comentarios
E/o comente el c2digo incorrecto, reescr+baloF"
(rian 5. ?ernig/an - P. J. Plaug/er;> Bo %a5 nada =s ;til @ue un coentario bien colocado. Bo %a5 nada @ue colase =s un ódulo @ue coentarios dog=ticos innecesarios. Bo %a5 nada =s da3ino @ue un coentario antiguo @ue roague entiras 5 desin#oración. Los coentarios no son coo la Lista de c%indler. Bo son ura bondad. -e %ec%o, en el e8or de los casos, son un al necesario. i los lengua8es de rograación #ueran =s e>resi6os o si udiéraos doinarlos ara e>resar nuestras intenciones, no necesitaríaos deasiados coentarios, uede @ue incluso ninguno. *l uso correcto de los coentarios erite coensar nuestra incaacidad ara e>resaos en el código. e usado la alabra incaacidad, a roósito. Los coentarios siere son #allos. -ebeos usarlos or@ue no siere sabeos cóo e>resaos sin ellos ero su uso no es oti6o de celebración. Cuando tenga @ue escribir un coentario, iense si no e>iste otra #ora de e>resarse en el código. iere @ue se e>rese en el código, debe #elicitarse. iere @ue escriba un coentario, debe %acer un gesto de desarobación 5 sentir su incaacidad ara e>resarse. H/or @ué esto5 en contra de los coentariosI /or@ue ienten. Bo siere 5 no siere intencionadaente, ero lo %acen. Cuando =s antiguo es un coentario 5 =s se ale8a del código @ue describe, a5or es la robabilidad de @ue sea e@ui6ocado. *l oti6o es sencillo. Los rograadores no los ueden antener.
*l código cabia 5 e6oluciona. Los #ragentos cabian de lugar, se bi#urcan, se reroducen 5 se 6uel6en a cobinar ara crear @uieras. -esa#ortunadaente, los coentarios no siere siguen el rito, no siere ueden %acerlo 5 suelen seararse del código @ue describen 5 se con6ierten en %uér#anos sin recisión alguna. /or e8elo, #í8ese en lo @ue sucede con este coentario 5 la línea @ue retendía describir: Moc&Re@uest re@uest ri6ate #inal tring TT/-(T*R*G*+/ X MT7U a1!U_`Ob2_`Od__,__s019U_`Ob2_`Od__sJM(t conte>t ri6ate ileResonder resonder ri6ate Locale sa6eLocale #)emploH 03ue* < Apr <licati6o. e odría a#irar @ue los rograadores deben ser lo bastante discilinados coo ara antener los coentarios actuali!ados, rele6antes rele6 antes 5 recisos. -e acuerdo, debería, deber ía, ero esa energía debería in6ertirse in6er tirse en crear código claro 5 e>resi6o e>res i6o @ue no necesite coentario alguno. Los coentarios irecisos son uc%o eor @ue la ausencia de coentarios. uelen con#undir al usuario. Generan e>ectati6as @ue nunca se culen. -e#inen reglas @ue no deben seguirse en absoluto. La 6erdad sólo se encuentra en un unto: el código. ólo el código uede contar lo @ue %ace. *s la ;nica #uente de in#oración recisa. /or tanto, aun@ue los coentarios sean necesarios en ocasiones, dedicareos nuestra energía a inii!arlos.
!os comentarios no compensan el código incorrecto na de las rinciales oti6aciones ara crear coentarios es el código incorrecto. Creaos un ódulo 5 sabeos @ue es con#uso 5 est= desorgani!ado. abeos @ue es un desastre 5 entonces decidios coentarlo. *rror. Me8or líielo. *l código claro 5 e>resi6o sin aenas coentarios es u5 suerior al código enre6esado 5 cole8o con ultitud de coentarios. *n lugar de erder tieo escribiendo coentarios @ue e>li@uen el desastre coetido, dedí@uelo a solucionarlo.
#Eplicarse en el código *n ocasiones, el código es un obre 6e%ículo de e>resión. -esa#ortunadaente, uc%os rograadores lo entienden coo @ue el código no es un buen edio de e>resión. *sto es #also. HKué re#iere 6erI *sto: QQ Corobar si el eleado tiene derec%o a todos los bene#icios i# elo5ee.#lags ' <RLEL(G4 '' elo5ee.age ^ N44 o esto otro:
i# elo5ee.is*ligibleorull)ene#its44 (enas se tardan unos segundos en e>licar nuestras intenciones en el código. *n uc%os casos, basta con crear una #unción @ue diga lo iso @ue el coentario @ue ensaba escribir.
Comentarios de calidad (lgunos coentarios son necesarios o bene#iciosos. ereos algunos de los @ue considero 6=lidos. Bo obstante, recuerde @ue el ;nico coentario realente bueno es el @ue no tiene @ue escribir.
Comentarios legales *n ocasiones, nuestros est=ndares cororati6os de creación de código nos obligan a crear deterinados coentarios or oti6os legales. /or e8elo, los coentarios de derec%os de autor son necesarios 5 deben incluirse al inicio de cada arc%i6o. *l siguiente encabe!ado de coentario se inclu5e de #ora est=ndar al inicio de todos los arc%i6os #uente de itBesse. Buestro "-* e6ita @ue este coentario are!ca sobrante releg=ndolo de #ora auto=tica. QQ Co5rig%t C4 200W,200V,200 de terno en lugar de incluir todos los térinos 5 condiciones en el coentario.
Comentarios informati+os *n ocasiones es ;til roorcionar in#oración b=sica con un coentario. /or e8elo, el siguiente coentario e>lica el 6alor de6uelto or un étodo abstracto: 2e+uel+e una instancia del elemento 4esponder probado. rotected abstract Resonder resonder"nstance4 *stos coentarios ueden ser ;tiles, ero es e8or usar el nobre de la #unción ara transitir la in#oración siere @ue sea osible. os ible. /or e8elo, en este caso el coentario sería redundante si cabiaos el nobre de la #unción or resonder)eingTested. eaos un e8elo e8or: QQ el #orato coincide con &&::ss ***, MMM dd, 5555 /attern tieMatc%er X /attern.coile __d:__d:__d __?, __? __d, __d4 *n este caso, el coentario nos indica @ue la e>resión regular debe coincidir con una #ec%a 5 una %ora con el #orato alicado or la #unción ile-ateorat.#orat con la cadena de #orato eseci#icada. ubiera resultado e8or 5 =s claro si el código se %ubiera cabiado a una clase
esecial @ue con6irtiera los #oratos de #ec%as 5 %oras. -e ese odo el coentario %abría sido suer#luo.
#Eplicar la intención *n ocasiones, un coentario es algo =s @ue in#oración ;til sobre la ileentación 5 roorciona la intención de una decisión. *n el siguiente caso, 6eos una interesante decisión docuentada or un coentario. (l coarar dos ob8etos, el autor decidió ordenar los ob8etos de su clase or encia de los ob8etos de otra. ublic int coareTocetion _`Ob 7idget)uilder ?idget)uilder X ne? 7idget)uilderne? ClassU)old7idget.class44 tring te>t X hhhbold te>thhh /arent7idget arent X ne? )old7idgetne? Moc&7idgetRoot4, hhhbold te>thhh4 (toic)oolean #aillag X ne? (toic)oolean4 #aillag.set#alse4 QQBuestro e8or intento de obtener una condición de carrera QQcreando un gran n;ero de rocesos. #or int i X 0 i ] 2000 iZZ4 _`Ob 7idget)uilderT%read ?idget)ui"derT%read X ne? 7idget)uilderT%read7idget)uilder, te>t, arent, #aillag4 T%read t%read X ne? T%read7idget)uilderT%read4 t%read.start4 _`Od assert*@uals#alse, #aillag.get44 _`Od
Clarificación *n ocasiones, basta con traducir el signi#icado de un arguento o 6alor de6uelto en algo =s legible. /or lo general, con6iene buscar la #ora de @ue el arguento o el 6alor de6uelto sean claros or sí isos ero cuando #ora arte de una biblioteca est=ndar o
de código @ue no se uede alterar, un coentario aclarati6o uede ser u5 ;til. ublic 6oid testCoareTo4 t%ro?s *>cetion _`Ob 7i&i/age/at% a X /at%/arser.arse/age(4 /at%/arser.arse/age (4 7i&i/age/at% ab X /at%/arser.arse/age(./age /at%/arser.arse/age(./age)4 )4 7i&i/age/at% b X /at%/arser.arse/age)4 7i&i/age/at% aa X /at%/arser.arse/age(./age(4 /at%/arser.arse/ag e(./age(4 7i&i/age/at% bb X /at%/arser.arse/age)./ag /at%/arser.arse/age)./age)4 e)4 7i&i/age/at% ba X /at%/arser.arse/age)./age( /at%/arser.arse/age)./age(4 4 assertTruea.coareToa4 XX 04 QQ a XX a assertTruea.coareTob4 X 04 QQ a X b assertTrueab.coareToab4 XX 04 QQ ab XX ab assertTruea.coareTob4 XX 14 QQ a ] b assertTrueaa.coareToab4 XX 14 QQ aa ] ab assertTrueba.coareTobb4 XX 14 QQ ba ] bb assertTrueb.coareToa4 XX 4 QQ b ^ a assertTrueab.coareTo aa4 XX 4 QQ ab ^ aa assertTruebb.coareToba4 XX 4 QQ bb ^ ba _`Od /ero tabién e>iste el riesgo de @ue un coentario aclarati6o sea incorrecto. *n el e8elo anterior, coruebe lo di#ícil @ue resulta corobar si los coentarios son correctos. *sto e>lica or @ué la clari#icación es necesaria 5 tabién arriesgada. /or ello, antes de escribir estos coentarios, aseg;rese de @ue no %a5 una solución e8or 5 tabién de @ue sean recisos.
Ad+ertir de las consecuencias
*n ocasiones es u5 ;til ad6ertir a otros rograadores de deterinadas consecuencias. /or e8elo, el siguiente coentario e>lica or @ué un deterinado caso de rueba est= desacti6ado: Bo e)ecutar a menos 9ue le sobre tiempo.
ublic 6oid test7it%Reall5)igile4 _`Ob ?riteLinesToile00000004 resonse.set)od5testile4 resonse.read5Toendt%is4 tring resonsestring X outut.totring4 assertubtringContent1Lengt%: 000000000, resonsetring4 assertTrueb5tesent ^ 0000000004 _`Od *n la actualidad, e6identeente, desacti6aríaos la rueba or edio del atributo ["gnore con la corresondiente cadena e>licati6a: ["gnoreTa&es too long to run4, ero antes de la aarición de Jnit V, era %abitual a3adir un guion ba8o delante del nobre del étodo. *l coentario reali!aba su coetido. eaos otro e8elo: ublic static ile-ateorat a&etandardtt-ateorat4 _`Ob Simple2ata$ormat no es compatible con procesos* por lo 9ue debe crear cada instancia de forma independiente. ile-ateorat d# X ne? ile-ateorat***, dd MMM 5555 ::ss !4 d#.setTieDone TieDone.getTieDone GMT44 return d# _`Od eguraente cono!ca soluciones e8ores ara este roblea. *sto5 de acuerdo, ero el coentario es er#ectaente ra!onable. ra!o nable. *6ita @ue un rograador use un iniciali!ador est=tico or oti6os de e#icacia.
Comentarios 3O2O *n ocasiones con6iene usar notas con #ora de coentarios QQT<-<. *n el siguiente caso, el coentario T<-< e>lica or @ué la #unción tiene una ileentación incorrecta 5 cu=l debe ser su #uturo. 3O2OFMdM no son necesarios #speramos 9ue desaparezca en el modelo definiti+o rotected ersion"n#o a&eersion4 t%ro?s t%ro ?s *>cetion _`Ob return null _`Od T<-< son tareas @ue el rograador iensa @ue debería %aber %ec%o ero @ue no es así. /ueden ser un recordatorio ara eliinar una #unción obsoleta o una etición ara resol6er un roblea. /ueden ser una solicitud ara buscar un nobre =s adecuado o ara reali!ar un cabio @ue deenda de un e6ento laneado. ea lo @ue sea, no es e>cusa ara antener código incorrecto en el sistea. *n la actualidad, uc%os "-* cuentan con #unciones eseciales ara locali!ar
coentarios T<-<, or lo @ue seguraente no se ierda. in ebargo, no colase el código con estos coentarios. *>aínelos 5 eliine todos los @ue ueda.
Amplificación e uede usar un coentario ara ali#icar la iortancia de algo @ue, en caso contrario, arecería irrele6ante. tring list"teContent X atc%.grouW4.tri4 el recorte es importante. #limina los espacios iniciales 9ue /ar:an 9ua el elemento se reconociera como otra lista. ne? List"te7idgett%is, list"teContent, t%is.le6el Z 4 return buildListte>t.substringatc%.end444
Ja+adoc en API pblicas Bo %a5 nada =s ;til 5 satis#actorio @ue una (/" ;blica bien descrita. Los 8a6adoc de la biblioteca est=ndar de Ja6a son un e8elo. ería u5 colicado crear rograas de Ja6a sin ellos. i usa una (/" ;blica, debe crear 8a6adoc de calidad ara la isa, ero recuerde el siguiente conse8o a lo largo del caítulo: los 8a6adoc ueden ser tan abiguos, alios 5 descorteses coo cual@uier otro tio de docuento.
Comentarios incorrectos Muc%os coentarios ertenecen a esta categoría. uelen ser e>cusas de código obre o 8usti#icaciones de decisiones insu#icientes, algo a lgo así coo si el rograador se %ablara a sí iso.
(albucear (3adir un coentario sin ra!ón o or@ue el roceso lo re@uiere es un error. i decide escribir un coentario, tóese el tieo necesario ara asegurarse de @ue sea el e8or @ue uede redactar. *l siguiente e8elo es de itBesse, donde un coentario sin duda sería de utilidad, ero el autor tenía risa o no restó deasiada deas iada atención. u balbuceo generó un eniga: en iga: ublic 6oid load/roerties4 _`Ob tr5 _`Ob tring roerties/at% X roertiesLocation Z Q Z /R*RT"*"L* ile"nuttrea roertiestrea X ne? ile"nuttrearoerties/at%4 loaded/roerties.loadroertiestrea4 _`Od
catc%"<*>cetion e4 _`Ob Si no /a- arc/i+os de propiedades significan 9ue cargan las predeterminadas
_`Od _`Od HKué signi#ica el coentario del blo@ue catc%I eguro @ue algo ara el autor, ero el signi#icado no est= claro. (arenteente, si se genera "<*>cetion, signi#ica @ue no %a5 arc%i6o de roiedades 5, en ese caso, se cargan los 6alores redeterinados. H/ero @uién carga los 6alores redeterinadosI He cargan antes de la in6ocación de load/roerties.load o load/roerties.load catura la e>ceción, carga los 6alores redeterinados 5 desués nos asa la e>ceción ara @ue la ignoreosI ignoreos I H< ser= @ue load/roerties.load carga todos los 6alores redeterinados antes de intentar abrir el arc%i6oI H"ntentaba el autor consolarse or de8ar el blo@ue catc% 6acíoI \sta es la osibilidad =s teida, Hse estaba diciendo @ue 6ol6iera =s tarde ara ara crear el código ara cargar los 6alores redeterinadosI redeterinadosI Buestro ;nico recurso es e>ainar el código en otras artes del sistea ara deterinar @ué sucede. Cual@uier coentario @ue le obligue a buscar su signi#icado en otro ódulo %a #allado en su intento de counicación 5 no erece los bits @ue consue.
Comentarios redundantes *l Listado V1 uestra una sencilla #unción con un coentario de encabe!ado totalente redundante. eguraente se tarde =s en leer @ue el roio código. !istado F
?aitorClose. MDtodo de utilidad de+uelto cuando t/is.closed es true. enera una eEcepción si se alcanza el tiempo de espera.
ublic s5nc%roni!ed 6oid ?aitorClose#inal long tieoutMillis4 t%ro?s *>cetion _`Ob i# closed4 _`Ob ?aittieoutMillis4 i#closed4 t%ro? ne? *>cetion Moc&Resonseender could not be closed4 _`Od _`Od H/ara @ué sir6e este coentarioI Bo es =s in#orati6o @ue el código. Bo lo 8usti#ica ni transite la intención ni la lógica. Bo es =s #=cil de leer @ue el código. -e %ec%o, es enos reciso 5 obliga al lector a acetar la #alta de recisión en lugar de a entenderlo. *s coo un 6endedor de coc%es de segunda enos @ue le asegura @ue no %ace #alta re6isar el otor.
í8ese a%ora en la legión de 8a6adoc in;tiles 5 redundantes del Listado V12, obtenido de Tocat. *stos coentarios ;nicaente ensucian 5 oscurecen el código. Bo tienen ninguna #unción docuental. /ara eeorar las cosas, sólo le ostraos algunos. *l ódulo tiene uc%os =s. !istado F Container)ase.8a6a Tocat4. ublic abstract class Container)ase ileents Container, Li#ec5cle, /ieline, M)eanRegistration, eriali!able _`Ob Q Retardo del rocesador ara este coonente. Q rotected int bac&ground/rocessor-ela5 X 1 Q Coatibilidad con e6entos de ciclo 6ital de este coonente. Q rotected Li#ec5cleuort li#ec5cle X ne? Li#ec5cleuortt%is4 Q *scuc%adores de e6entos de contenedor de este contenedor. Q rotected (rra5List listeners X ne? (rra5List4 Q "leentación Loader a la @ue se asocia este contenedor. Q rotected Loader loader X null Q "leentación Logger a la @ue se asocia este contenedor. Q rotected Log logger X null Q Bobre de registrador asociado. Q rotected tring logBae X null Q "leentación Manager a la @ue se asocia este contenedor. Q rotected Manager anager X null Q Cl;ster al @ue se asocia este contenedor. Q rotected Cluster cluster X null Q Bobre legible de este contenedor. Q rotected tring nae X null
Q Contenedor rincial de este contenedor. Q rotected Container arent X null Q Cargador de clase rincial @ue con#igurar al instalar un eleento Loader. Q rotected ClassLoader arentClassLoader X null Q t de recursos al @ue se asocia este contenedor. Q rotected -irConte>t resources X null
Comentarios confusos *n ocasiones, a esar de las buenas intenciones, un rograador reali!a una a#iración en sus coentarios @ue no es del todo recisa. í8ese otra 6e! en el coentario redundante 5 con#uso del Listado V1. Habe or @ué es con#usoI *l étodo no de6uel6e nada cuando t%is.closed se con6ierte en true. -e6uel6e algo si t%is.closed es true en caso contrario, esera 5 genera una e>ceción si t%is.closed no es true. *ste sutil #ragento, oculto en un coentario =s di#ícil de leer @ue el cuero del código, uede %acer @ue otro rograador in6o@ue la #unción con la eseran!a de @ue de6uel6a algo cuando t%is.closed sea true. *se obre rograador se encontrar= en una sesión de deuración intentando deterinar or @ué el código se e8ecuta tan lentaente.
Comentarios obligatorios *s una locura tener una regla @ue a#ire @ue todas las #unciones deben tener un 8a6adoc o @ue todas las 6ariables deben tener un coentario. *ste tio de coentarios ensucian el código 5 generan con#usión 5 desorgani!ación. /or e8elo, los 8a6adoc obligatorios ara todas las #unciones crean aboinaciones coo el Listado V1W. Bo sir6en de nada, colican el código 5 constitu5en osibles enga3os 5 desorientaciones. !istado FG Q
[ara title *l título del C [ara aut%or *l autor del C [ara trac&s *l n;ero de istas del C [ara duration"nMinutes La duración del C- en inutos Q ublic 6oid addC-tring title, tring aut%or, int trac&s, int duration"nMinutes4 _`Ob C- cd X ne? C-4 cd.title X title cd.aut%or X aut%or cd.trac&s X trac&s cd.duration X duration cdList.addcd4 _`Od
Comentarios periódicos *n ocasiones, se a3ade un coentario al inicio de un ódulo cada 6e! @ue se edita. *stos coentarios acuulan una esecie de registro de todos los cabios reali!ados. e 6isto ódulos con decenas de =ginas con estas entradas. Cabios 1
Comentarios sobrantes *n ocasiones 6eos coentarios @ue sileente sobran. Restan iortancia a lo e6idente 5 no o#recen in#oración nue6a. Q Constructor redeterinado. Q rotected (nnual-ateRule4 _`Ob
_`Od H*n serioI HE este otroI: Q -ía del es. Q ri6ate int da5<#Mont% E a@uí el arangón de la redundancia: Q -e6uel6e el día del es. [return el día del es. Q ublic int get-a5<#Mont%4 _`Ob return da5<#Mont% _`Od *stos coentarios son tan inser6ibles @ue arendeos a ignorarlos. (l leer el código, la 6ista los salta. Con el tieo, los coentarios eie!an a entir cuando cabia el código @ue les rodea. *l rier coentario del Listado V1V arece correcto2U. *>lica or @ué se ignora el blo@ue catc%, ero el segundo coentario sobra. /arece @ue el rograador estaba tan #rustrado con crear blo@ues tr5Qcatc% en la #unción @ue necesitaba e>lotar. !istado F
startending. ri6ate 6oid startending4 _`Ob tr5 _`Ob doending4 _`Od catc%oc&et*>cetion e4 _`Ob normal* alguien /a detenido la solicitud. _`Od catc%*>cetion e4 _`Ob tr5 _`Ob resonse.add*rrorResonder.a&e*>cetiontringe44 resonse.close(ll4 _`Od catc%*>cetion e4 _`Ob 8n respiro _`Od _`Od _`Od
*n lugar de e>lotar en un coentario sin sentido, el rograador debería %aber sabido @ue su #rustración se odría ali6iar e8orando la estructura del código. Tendría @ue %aber centrado su energía en e>traer el ;ltio blo@ue tr5Qcatc% en una #unción indeendiente, coo uestra el Listado V1. !istado F startending re#actori!ado4. ri6ate 6oid startending4 _`Ob tr5 _`Ob doending4 _`Od catc%oc&et*>cetion e4 _`Ob QQ noral. (lguien %a detenido la solicitud. _`Od catc%*>cetion e4 _`Ob add*>cetion(ndCloseResonsee4 _`Od _`Od ri6ate 6oid add*>cetion(ndCloseResonse*>cetion e4 _`Ob tr5 _`Ob resonse.add*rrorResonder.a&e*>cetiontringe44 resonse.close(ll4 _`Od catc%*>cetion e4 _`Ob _`Od _`Od Cabie la tentación de crear eleentos sobrantes or la deterinación de liiar su código. Me8orar= coo rograador 5 ser= =s #=cil.
Comentarios sobrantes espeluznantes Los 8a6adoc tabién ueden ser innecesarios. H/ara @ué sir6en los siguientes 8a6adoc de una conocida biblioteca4 de código cód igo abiertoI La resuesta: ara nada. on coentarios redundantes creados en un intento e@ui6ocado de redactar docuentación. Q *l nobre. Q ri6ate tring nae Q La 6ersión. Q ri6ate tring 6ersion Q *l licenceBae. Q
ri6ate tring licenceBae Q La 6ersión. Q ri6ate tring in#o uel6a a leer los coentarios. H-etecta el error de corta 5 egaI i los autores no restan atención al escribir sus coentarios o o al egarlos4, Hor @ué se esera es era @ue sean de utilidad ara los lectoresI
Bo usar comentarios si se puede usar una función o una +ariable í8ese en el siguiente código: QQ Hel ódulo de la lista global ]od^ deende del QQ subsistea del @ue #oraos arteI i# sodule.get-eendubs5stes4.containss sodule.get-eendubs5stes4.containssub5sMod.getubs5ste444 ub5sMod.getubs5ste444 e odría cabiar sin el coentario de esta #ora: (rra5List odule-eendees X sodule.get-eendubs5stes4 tring ourub5ste X sub5sMod.getub5ste4 i# odule-eendees.containsourub5ste44 *l autor del código original seguraente escribió riero el coentario irobable4 5 desués el código ara a8ustarlo al coentario. in ebargo, el autor tendría @ue %aber re#actori!ado el código, coo %ice 5o, ara oder eliinar el coentario.
Marcadores de posición *n ocasiones los rograadores arcan una deterinada osición en un arc%i6o. /or e8elo, recienteente encontré esto en un rograa: QQ (cciones QQQQQQQQQQQQQQQQQQQQQQQ QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ QQQQQQQQQQQ on escasas las ocasiones en las @ue tiene sentido agruar #unciones ba8o esta estructura. /or lo general, debe eliinarse, sobre todo la olesta %ilera de barras al #inal. /iénselo de esta #ora. *stas estructuras son atracti6as si no las usa deasiado. /or ello, ;selas esor=dicaente 5 sólo cuando el bene#icio sea signi#icati6o. i las usa en e>ceso, acabar=n or ser ignoradas.
Comentarios de lla+e de cierre *n ocasiones, los rograadores inclu5en coentarios eseciales en lla6es de cierre, coo en el Listado V1N. (un@ue ueda tener sentido en #unciones e>tensas con estructuras anidadas, ;nicaente estorba a las #unciones encasuladas 5 de e@ue3o taa3o @ue nos gustan. /or ello, si siente el deseo de arcar sus lla6es de cierre, ruebe a reducir el taa3o de sus #unciones. !istado FL
?c.8a6a. ublic class ?c _`Ob ublic static 6oid aintringU args4 _`Ob )u##eredReader in X ne? )u##eredReaderne? "nutstreaReader5ste.in44
tring line int lineCount X 0 int c%arCount X 0 int ?ordCount X 0 tr5 _`Ob ?%ile line X in.readLine44 X null4 _`Ob lineCountZZ c%arCount ZX line.lengt%4 tring ?ordsU X line.slit__74 ?ordCount ZX ?ords.lengt% _`Od w/ile 5ste.out.rintln ?ordCount X Z ?ordCount4 5ste.out.rintln lineCount X Z lineCount4 5ste.out.rintlnc%arCount Z c%arCount4 _`Od trcatc% "<*>cetion e4 _`Ob 5ste.err.rintln *rror: Z e.getMessage44 _`Od catc/ _`Od main _`Od
Asignaciones - menciones Q (3adido or Ric& Q Los sisteas de control de código #uente recuerdan a la er#ección @uién %a a3adido @ué 5 cu=ndo. Bo es necesario lagar el código con e@ue3as enciones. /uede ensar @ue estos coentarios son ;tiles 5 @ue a5udan a otros a %ablar sobre el código, ero en realidad sobre6i6en durante a3os 5 cada 6e! son enos recisos 5 rele6antes. *l sistea de control de código #uente es el unto idóneo ara este tio de in#oración.
Código comentado Bo %a5 nada =s odioso @ue el código coentado. fBo lo %aga "nuttreaResonse resonse X ne? inuttreaResonse4 resonse.set)od5#oratter.getResulttrea4, #oratter.get)5teCount44 InputStream resultsStream Q formatter.get4esultStreamRT Stream4eader reader Q new Stream4eaderRresultsStreamT response.setContentRreader.readRformatter.get(-t response.setContentRrea der.readRformatter.get(-teCountRT eCountRT Los lectores @ue 6ean código coentado no tendr=n el 6alor de borrarlo. /ensar=n @ue est= a%í or algo 5 @ue es deasiado iortante ara borrarlo. /or ello, el código coentado se acuula coo los sedientos en una botella de 6ino alo. í8ese en este #ragento de aac%e coons: t%is.b5te/os X ?rite)5tesng"d)5tes, 04 /drPos Q b-tePosT
?riteeader4 ?riteResolution4 dataPos Q b-tePosT
i# ?rite"age-ata 44 _`Ob ?rite*nd4 t%is.ng)5tes X resi!e)5te(rra5t%is.ng)5tes, t%is.a>/os4 _`Od else _`Ob t%is.ng)5tes X null _`Od return t%is.ng)5tes H/or @ué %a5 dos líneas coentadasI Hon iortantesI He %an conser6ado coo recordatorio de un cabio ininente o es algo @ue alguien coentó %ace a3os 5 no se %a reocuado de liiarI ubo una éoca, en la década de 9N0, en la @ue el código coentado udo ser ;til, ero %ace tieo @ue contaos con buenos sisteas de control de código #uente, sisteas @ue recuerdan el código or nosotros. Ea no teneos @ue coentarlo. *liínelo. Bo lo erder=. e lo aseguro.
Comentarios "3M! *l TML en coentarios de código #uente es una aberración, coo uede areciar en el siguiente #ragento. -i#iculta la lectura de los coentarios donde debería ser =s #=cil el editor o "-*. i los coentarios se 6an a e>traer con una %erraienta coo Ja6adoc4 ara ostrarlos en una =gina 7eb, debe ser resonsabilidad de dic%a %erraienta 5 no del rograador el adornar los coentarios con el corresondiente TML.
UU U 3area para e)ecutar pruebas de aceptación. U #sta tarea e)ecuta pruebas de aceptación - publica los resultados. U VpW U VpreW U 8soH U XltTtas6def nameQX9uotTeEecuteFfitnesseFtestsX9uotT U classnameQX9uotTfitnesse.ant.#Eecute$itnesse3ests3as6X9uotT U classpat/refQX9uotTclasspat/X9uotT XgtT U O4 U XltTtas6def classpat/refQX9uotTclasspat/X9uotT U resourceQX9uotTtas6s.propertiesX9uotT XgtT U VpW U XltTeEecuteF fitnesseFtests U suitepageQX9uotT$itBesse.SuiteAcceptance3estsX9uotT U fitnesseportQX9uotTNto de un coentario local. í8ese en el siguiente coentario 8a6adoc. (arte de su terrible redundancia, tabién o#rece
in#oración sobre el uerto redeterinado 5 la #unción no tiene control alguno sobre el uerto redeterinado. *l coentario no describe descr ibe la #unción sino otra arte distinta del sistea. *6identeente, no %a5 garantías de @ue el coentario cabie cuando lo %aga el código @ue contiene el 6alor redeterinado. Q /uerto ara e8ecutar #itnesse. *l redeterinado es ]b^A0A2]Qb^. [ara #itnesse/ort Q ublic 6oid setitnesse/ortint #itnesse/ort4 _`Ob t%is.#itnesse/ort X #itnesse/ort _`Od
2emasiada información Bo inclu5a en sus coentarios interesantes re#le>iones %istóricas ni irrele6antes descriciones de detalles. *l siguiente coentario se %a e>traído de un ódulo dise3ado ara robar @ue una #unción # unción uede codi#icar 5 descodi#icar baseNV. b aseNV. (arte del n;ero RC, el lector de este código no necesita la in#oración obsoleta @ue contiene el coentario. Q RC 20V 1 *>tensiones Multiroósito de correo de "nternet M"M*4 /riera arte: orato del Cuero de los Mensa8es de "nternet sección N.A. Codi#icación de trans#erencia de contenidos )aseNV *l roceso de codi#icación reresenta gruos de 2V bits de la entrada coo cadenas de salida de V caracteres codi#icados. /rocediendo de i!@uierda a derec%a, se #ora un gruo de 2V bits de entrada concatenando W gruos de A bits de entrada. *stos 2V bits se tratan coo V gruos concatenados de N bits, cada uno de los cuales se traduce en un solo dígito del al#abeto baseNV. Cuando se codi#ica un #lu8o de bits ediante la codi#icación baseNV, el #lu8o de bits se debe considerar ordenado con el bit =s signi#icati6o riero. *sto es, el rier bit del #lu8o ser= el bit de orden =s alto en el rier b5te de A bits, 5 el octa6o bit ser= el de orden =s ba8o en el rier b5te de A bits, 5 así sucesi6aente. Q
ConeEiones no e+identes La cone>ión entre un coentario 5 el código @ue describe debe ser e6idente. i se %a reocuado de escribir un coentario, lo ínio es @ue el lector @ue lo 6ea entienda a @ué se re#iere. í8ese en este coentario obtenido de aac%e coons: Q coien!a con una atri! de taa3o su#iciente ara albergar todos los i>eles =s b5tes de #iltro4, 5 200 b5tes adicionales ara la in#oración de encabe!ado
Q t%is.ng)5tes X ne? b5tet%is.?idt% Z 4 t%is.%eig%t W4 Z 200U HKué es un b.te de #iltroI H*st= relacionado con ZI H< con WI HCon abosI H*s un i>el un b.teI H/or @ué 200I La #unción de un coentario es e>licar código @ue no se e>lica or sí iso. *s una l=stia @ue un coentario re@uiera su roia e>licación.
#ncabezados de función Las #unciones bre6es aenas re@uieren e>licación. n nobre bien elegido ara una #unción @ue %ace una cosa suele ser e8or @ue un encabe!ado de coentario.
Ja+adocs en código no pblico ( esar de la utilidad de los 8a6adoc ara las (/" ;blicas, no sir6en ara código no dirigido a consuo ;blico. La generación de =ginas 8a6adoc ara clases 5 #unciones de un sistea no suele ser ;til 5 la #oralidad adicional de los coentarios 8a6adoc no es =s @ue una distracción.
#)emplo *scribí el ódulo del Listado V1O ara la riera 6ersión de P 3mmersion. -ebía ser un e8elo de estilo incorrecto de creación de código 5 coentarios. -esués, $ent )ec& re#actori!ó este código en algo uc%o =s atracti6o delante de 6arios alunos. /osteriorente, adaté el e8elo ara i libro Agile Software Development, Principles, Patterns, and Practices 5 ara el riero de is artículos Craftsman ublicados en la re6ista Software Development . Lo @ue e #ascina de este ódulo es @ue %ubo un tieo en @ue uc%os lo %ubiéraos considerado bien docuentado. (%ora 6eos @ue es un auténtico desastre. ( 6er cu=ntos robleas detecta en los coentarios. !istado F=
Generate/ries.8a6a. Q *sta clase genera n;eros rios %asta la cantidad =>ia eseci#icada or el usuario. *l algorito usado es la Criba de *ratóstenes. ]^ *ratóstenes de Cirene, 2ON a. C., Cirene, Libia 1 9V a. C., (le8andría. *l rier %obre en calcular la circun#erencia de la Tierra. Tabién traba8ó con calendarios con a3os bisiestos 5 #ue resonsable de la )iblioteca de (le8andría. ]^ *l algorito es u5 sile. -ada una atri! de enteros ee!ando or el 2, se tac%an todos los ;ltilos de 2. e busca el siguiente entero sin tac%ar 5 se tac%an todos sus ;ltilos. Reetir %asta suerar la raí! cuadrada del 6alor
=>io. Saut%or (l%onse S6ersion W eb 2002 at Q iort 8a6a.util. ublic class Generate/ries _`Ob Q [ara a>alue es el líite de generación. Q ublic static intU generate/riesint a>alue4 _`Ob i# a>alue ^X 24 QQel ;nico caso 6=lido _`Ob QQ declaraciones int s X a>alue Z QQ taa3o de la atri! booleanU # X ne? booleansU int i QQ iniciali!ar la atri! en true. #or i X 0 i ] s iZZ4 #iU X true QQ eliinar los n;eros no rios conocidos #0U X #U X #alse QQ cribar int 8 #or i X 2 i ] Mat%.s@rts4 Z iZZ4 _`Ob i# #iU4 QQ si no est= tac%ado, tac%ar sus ;ltilos. _`Ob #or 8 X 2 i 8 ] s 8 ZX i4 #8U X #alse QQ el ;ltilo no es rio _`Od _`Od QQ Hcu=ntos rios %a5I int count X 0 #or i X 0 i ] s iZZ4 _`Ob i# #iU4 countZZ QQ contador. _`Od intU ries X ne? intcountU QQ en6iar rios al resultado #or i X 0, 8 X 0 i ] s iZZ4 _`Ob i# #iU4 QQ si es rio ries8ZZU X i
_`Od return ries QQ de6ol6er los rios _`Od else QQ a>alue ] 2 return ne? int0U QQ de6ol6er atri! null si la entrada no es correcta. _`Od _`Od *n el Listado V1A uede 6er una 6ersión re#actori!ada del iso ódulo. e %a liitado considerableente el uso de coentarios. a5 sólo dos en todo el ódulo 5 abos claraente descriti6os. !istado FN
/rieGenerator.8a6a re#actori!ado4. Q *sta clase genera n;eros rios %asta la cantidad =>ia eseci#icada or el usuario. *l algorito usado es la Criba de *ratóstenes. -ada una atri! de enteros ee!ando or el 2: buscar el rier entero sin tac%ar 5 tac%ar todos sus ;ltilos. Reetir %asta @ue no %a5a =s ;ltilos en la atri!. Q ublic class /rieGenerator _`Ob ri6ate static booleanU crossedalue4 _`Ob i# a>alue ] 24 return ne? int0U else _`Ob uncross"ntegersToa>alue4 crossalue4 _`Ob crossedalue Z U #or int i X 2 i ] crossed
_`Od ri6ate static int deterine"terationLiit4 _`Ob QQ Cada ;ltilo en la atri! tiene un #actor riordial @ue QQ es enor o igual @ue la raí! del taa3o de la atri!, QQ entonces no teneos @ue tac%ar ;ltilos de n;eros QQ =s grande @ue esa raí!. double iterationLiit X Mat%.s@rtcrossedlica la lógica del uso de la raí! cuadrada coo líite del bucle. Bo encontré otro nobre de 6ariable =s sencillo ni otra estructura de código @ue lo aclarara =s. /or otra arte, el uso de la raí! cuadrada odría resultar resuntuoso. HRealente se a%orra tanto tieo liitando la iteración a la raí! cuadradaI H*l c=lculo de la raí! cuadrada lle6aría =s tieo del @ue se a%orraI Con6iene anali!arlo. *l uso de la raí! cuadrada coo líite de iteración satis#ace al 6ie8o hacker de de C 5 de lengua8es de ensablado de i interior, ero no esto5 con6encido de @ue ere!ca el tieo 5 el es#uer!o @ue los de=s uedan dedicar a entenderlo.
(ibliograf:a ;?P=N>: $ernig%an and /laug%er, $he )lements of Programming St.le, 2d. ed., McGra?1ill, 9OA.
$ormato
Cuando los usuarios iran entre bastidores, @uereos @ue @ueden iresionados or el atracti6o, la co%erencia 5 la atención al detalle @ue erciben. Kuereos @ue el orden les sorrenda, @ue abran los o8os con asobro cuando se deslacen or los ódulos. Kuereos @ue arecien @ue se trata de un traba8o de ro#esionales. i 6en una asa aor#a de código @ue arece escrito or un gruo de arineros borrac%os, es robable @ue iensen @ue suceder= lo iso en otros asectos del ro5ecto. -ebe reocuarse or el #orato de su código. -ebe elegir una serie de reglas sencillas @ue controlen el #orato del código 5 desués alicarlas de #ora co%erente. i traba8a en e@uio, debe acordar una serie de reglas @ue todos los iebros deben culir. Tabién es u5 ;til usar una %erraienta autoati!ada @ue se encargue de alicar las reglas.
!a función del formato *n rier lugar, debe ser claro. *l #orato de código es iortante, deasiado
iortante coo ara ignorarlo 5 tabién deasiado iortante coo ara tratarlo de #ora religiosa. *l #orato del código se basa en la counicación 5 la counicación debe ser el rincial ilar de un desarrollador ro#esional. /uede @ue iense @ue conseguir @ue algo #uncione es la rincial reocuación de un rograador ro#esional. *sero @ue este libro le %aga cabiar de idea. La #uncionalidad @ue cree %o5 es u5 robable @ue cabie en la siguiente 6ersión, ero la legibilidad de su código a#ectar= ro#undaente a todos los cabios @ue realice. *l estilo del código 5 su legibilidad establecen los recedentes @ue a#ectan a la caacidad de anteniiento 5 aliación uc%o desués de @ue el código cabie. u estilo 5 su discilina sobre6i6ir=n, aun@ue el código no lo %aga. eaos @ué asectos del #orato nos eriten counicaos e8or.
$ormato +ertical Coenceos or el taa3o 6ertical. HKué taa3o debe tener un arc%i6o #uenteI *n Ja6a, el taa3o de los arc%i6os est= relacionado con el taa3o de las clases, coo 6ereos =s adelante. /or el oento, nos detendreos en el taa3o de los arc%i6os. HKué taa3o tienen la a5oría de arc%i6os #uente de Ja6aI *>iste una alia gaa de taa3os e iortantes di#erencias de estilo, coo se arecia en la #igura ..
igura .. *scala Lia 5 ínia de cada ro5ecto. *l cuadro uestra aro>iadaente un tercio una des6iación est=ndar 2NU4 de los arc%i6os. La arte central del cuadro es la edia. /or tanto, el taa3o de arc%i6o edio del ro5ecto itBesse es de N líneas 5 un tercio de los arc%i6os ocuan entre V0 5 00Z líneas. *l a5or arc%i6o de itBesse tiene unas V00 líneas 5 el de enor taa3o, N. *s una escala de registro, de odo @ue la e@ue3a di#erencia de osición 6ertical suone una gran di#erencia en taa3o absoluto.
Junit, itBesse 5 Tie and Mone5 tienen arc%i6os relati6aente e@ue3os. Binguno suera las 00 líneas 5 la a5oría tienen enos de 200. Tocat 5 (nt, or su arte, tienen arc%i6os con 6arios iles de líneas de longitud 5 =s de la itad sueran las 200. HKué signi#ica todo estoI (arenteente se ueden crear sisteas itBesse se aro>ia a las 0 000 líneas4 a artir de arc%i6os de unas 200 líneas de longitud, con un líite =>io de 00. (un@ue no debería ser una regla, es un inter6alo aconse8able. Los arc%i6os de e@ue3o taa3o se entienden e8or @ue los grandes.
!a metáfora del periódico /iense en un artículo de eriódico bien escrito. *n la arte suerior esera un titular @ue indi@ue de @ué se trata la %istoria 5 le erita deterinar si @uiere leerlo o no. *l rier =rra#o o#rece una u na sinosis de la %istoria, oculta los detalles 5 uestra concetos generales. (l a6an!ar la lectura, auentan los detalles 8unto con todas las #ec%as, nobres, citas 5 otros eleentos. n arc%i6o de código debe ser coo un artículo de eriódico. *l nobre debe ser sencillo ero claro. /or sí iso, debe bastar ara indicarnos si estaos o no en el ódulo correcto. Los eleentos sueriores del arc%i6o deben roorcionar concetos 5 algoritos de ni6el suerior. Los detalles deben auentar seg;n a6an!aos, %asta @ue en la arte #inal encontreos las #unciones de ni6el in#erior del arc%i6o. n eriódico se coone de 6arios artículos, algunos u5 reducidos 5 otros de gran taa3o. Bo %a5 uc%os @ue ocuen toda la =gina con te>to, ara @ue el eriódico sea ane8able. i el eriódico #uera un ;nico 5 e>tenso te>to con una agloeración desorgani!ada de %ec%os, #ec%as 5 nobres, no lo leeríaos.
Apertura +ertical entre conceptos La r=ctica totalidad del código se lee de i!@uierda a derec%a 5 de arriba a aba8o. Cada línea reresenta una e>resión o una cl=usula, 5 cada gruo de líneas reresenta un ensaiento coleto. *stos ensaientos deben seararse sear arse ediante líneas en blanco. í8ese en el Listado 1. a5 líneas en blanco @ue searan la declaración del a@uete, las iortaciones 5 las #unciones. *s una regla u5 sencilla con un ro#undo e#ecto en el dise3o 6isual del código. Cada línea en blanco es una ista 6isual @ue identi#ica un nue6o conceto indeendiente. (l a6an!ar or el listado, la 6ista se #i8a en la riera línea @ue aarece tras una línea en blanco. !istado F
)old7idget.8a6a ac&age #itnesse.?i&ite>t.?idgets iort 8a6a.util.rege>. ublic class )old7idget e>tends /arent7idget _`Ob ublic static #inal tring R*G*+/ X hhh.ZIhhh ri6ate static #inal /attern attern X /attern.coile hhh.ZI4hhh, /attern.MLT"L"B* Z /attern.-
ublic )old7idget/arent7idget arent. tring te>t4 t%ro?s *>cetion _`Ob suerarent4 Matc%er atc% X attern.atc%erte>t4 atc%.#ind4 addC%ild7idgetsatc%.grou44 _`Od ublic tring render4 t%ro?s *>cetion _`Ob tring)u##er %tl X ne? tring)u##er]b^4 %tl.aendc%ildtl44.aend ]Qb^4 return %tl.totring4 _`Od _`Od i eliinaos las líneas en blanco, coo en el Listado 12, se oscurece la legibilidad del código. !istado F
)old7idget.8a6a ac&age #itnesse.?i&ite>t.?idgets iort 8a6a.util.rege>. ublic class )old7idget e>tends /arent7idget _`Ob ublic static #inal tring R*G*+/ X hhh.ZIhhh ri6ate static #inal /attern attern X /attern.coilehhh.ZI4hhh, /attern.MLT"L"B* Z /attern.-t4 t%ro?s *>cetion _`Ob suerarent4 Matc%er atc% X attern.atc%erte>t4 atc%.#ind4 addC%ild7idgetsatc%.grou44_`Od ublic tring render4 t%ro?s *>cetion _`Ob tring)u##er %tl X ne? tring)u##er]b^4 %tl.aendc%ildtl44.aend]Qb^4 return %tl.totring4 _`Od _`Od *ste e#ecto auenta toda6ía =s si no centraos la 6ista. *n el rier e8elo, los distintos gruos de líneas saltan a la 6ista, ientras @ue en el segundo es una e!cla aor#a. La di#erencia entre abos listados es una ligera aertura 6ertical.
2ensidad +ertical i la aertura seara los concetos, la densidad 6ertical ilica asociaciones. /or tanto, las líneas de código con una relación directa deben aarecer 6erticalente densas. í8ese en cóo los coentarios sin sentido del Listado 1W anulan la asociación entre las dos 6ariables de instancia. !istado FG
ublic class ReorterCon#ig _`Ob Q Bobre de clase del escuc%ador Q ri6ate tring classBae Q /roiedades del escuc%ador Q ri6ate List]/roert5^ roerties X ne? (rra5List]/roert5^4 ublic 6oid add/roert5/roert5 roert54 _`Ob roerties.addroert54 _`Od *l Listado 1V es uc%o =s #=cil de leer. Lo areciaos a sile 6ista o al enos 5o lo %ago. (l irarlo, 6eo @ue es una clase con dos 6ariables 5 un étodo, sin tener @ue o6er la cabe!a ni la 6ista. *l listado anterior nos obliga a #or!ar la 6ista 5 a o6er la cabe!a ara alcan!ar el iso ni6el de corensión. !istado F
ublic class ReorterCon#ig _`Ob ri6ate tring classBae ri6ate List]/roert5^ roerties X ne? (rra5List]/roert5^4 ublic 6oid add/roert5/roert5 roert54 _`Ob roerties.addroert54 _`Od
2istancia +ertical H(lguna 6e! %a tenido @ue recorrer una clase, saltando de una #unción a otra, desla!=ndose or el código ara intentar adi6inar la relación 5 el #uncionaiento de las #unciones, 5 acabar totalente con#undidoI H(lguna 6e! %a escudri3ado la cadena de %erencia buscando la de#inición de una 6ariable o #unciónI Resulta #rustrante or@ue intenta corender lo @ue %ace el sistea, ero ierde el tieo 5 su energía ental en intentar locali!ar 5 recordar sus eleentos. Los concetos relacionados entre sí deben antenerse 8untos 6erticalente G0U. *sta regla no #unciona con concetos de arc%i6os indeendientes. /or lo tanto, no debe searar concetos relacionados en arc%i6os indeendientes a enos @ue tenga un oti6o de eso. -e %ec%o, es uno de los oti6os or or los @ue se debe e6itar el uso de 6ariables 6ariab les rotegidas. /ara los concetos relacionados @ue ertenecen al iso arc%i6o, su searación 6ertical debe edir su iortancia con resecto a la legibilidad del otro. -ebe e6itar @ue el lector deabule entre arc%i6os 5 clases. 2eclaraciones 2eclaraciones de +ariables Las 6ariables deben declararse de la #ora =s aro>iada a su uso. Coo las #unciones son u5 bre6es, las 6ariables locales deben aarecer en la arte suerior de cada
#unción, coo en este e8elo de JunitV.W.. ri6ate static 6oid read/re#erences4 _`Ob InputStream is Q nullT tr5 _`Ob is X ne? ile"nuttreaget/re#erencssile44 set/re#erencesne? /roertiesget/re#erences444 /roertiesget/re#erences4 44 get/re#erences4.loadis4 _`Od catc% "<*>cetion e4 _`Ob tr5 _`Ob i# is X null4 is.close4 _`Od catc% "<*>cetion e4 _`Ob _`Od _`Od _`Od Las 6ariables de control de bucles deben declararse en la instrucción del bucle, coo en esta e@ue3a #unción del iso código #uente: ublic int countTestCases4 _`Ob int countX 0 #or 3est eac/ : tests4 count ZX eac%.countTestCases4 return count _`Od *n casos e>cecionales, una 6ariable uede declararse en la arte suerior de un blo@ue o antes de un bucle en una #unción #un ción e>tensa. /uede 6er este tio de 6ariable en la siguiente #unción de TestBG. Y #or +lTest test: suite.getTests44 _`Ob 3est4unner tr Q mZrunner$actor-.new3est4unnerRt/is* testT
tr.addListenerte>tReorter4 testRunners.addtr4 in6o&er X tr.get"n6o&er4 #or "TestBGMet%od : tr.get)e#oreuiteMet%ods44 _`Ob be#oreuiteMet%ods.ut.getMet%od4, 4 _`Od #or "TestBGMet%od : tr.get(#teruiteMet%ods44 _`Ob a#teruiteMet%ods.ut.getMet%od4, 4 _`Od _`Od Y Kariables de instancia Las 6ariables de instancia, or su arte, deben declararse en la arte suerior de la clase. *sto no debe auentar la distancia 6ertical de las 6ariables, 5a @ue en una clase bien
dise3ada se usan en uc%os sino en todos sus étodos. *>isten discreancias sobre la ubicación de las 6ariables de instancia. *n CZZ suele alicarse la denoinada regla de las ti8eras, @ue sit;a todas las 6ariables de instancia en la arte in#erior. *n Ja6a, sin ebargo, es %abitual ubicarlas en la arte suerior de la clase. Bo 6eo oti6os ara no %acerlo. Lo iortante es declarar d eclarar las 6ariables de instancia en un unto conocido ara @ue todo el undo sea s ea dónde buscarlas. í8ese en el e>tra3o caso de la clase Testuite de Jnit V.W.. e atenuado considerableente esta clase ara ilustrar este conceto. i se #i8a en la itad del listado, 6er= dos 6ariables de instancia declaradas. Resultaría colicado ocultarlas en un unto e8or. Cual@uiera @ue lea este código tendría @ue toarse con las declaraciones or casualidad coo e asó a í4. ublic class Testuite ileents Test _`Ob static ublic Test createTestClass]I e>tends TestCase^ t%eClass, tring nae4 _`Ob Y _`Od ublic static Constructor]I e>tends TestCase^ getTestConstructorClass]I e>tends TestCase^ t%eClass4 t%ro?s Bouc%Met%od*>cetion _`Ob Y _`Od ublic static Test ?arning#inal tring essage4 _`Ob Y _`Od ri6ate static tring e>cetionTotringT%ro?able t4 _`Ob Y _`Od pri+ate String fBameT
pri+ate KectorV3estW f3ests Q new KectorV3estWR<T ublic Testuite4 _`Ob _`Od ublic Testuite#inal Class]I e>tends TestCase^ t%eClass4 _`Ob Y _`Od ublic TestuiteClass]I e>tends TestCase^ t%eClass, tring nae4 _`Ob Y _`Od YYYY _`Od $unciones dependientes i una #unción in6oca otra, deben estar 6erticalente ró>ias, 5 la #unción de in6ocación debe estar or encia de la in6ocada siere @ue sea osible. -e este odo el rograa #lu5e con noralidad. i la con6ención con6enc ión se sigue de #ora #iable, los lectores
sabr=n @ue las de#iniciones de #unción aarecen desués de su uso. í8ese en el #ragento de itBesse del Listado 1. La #unción suerior in6oca las situadas or deba8o @ue, a su 6e!, in6ocan a las siguientes. *sto #acilita la detección de las #unciones in6ocadas 5 e8ora considerableente la legibilidad del ódulo coleto. !istado F
7i&i/ageResonder.8a6a. ublic class 7i&i/ageResonder ileents ecureResonder _`Ob rotected 7i&i/age age rotected /age-ata age-ata rotected tring ageTitle rotected Re@uest re@uest rotected /ageCra?ler cra?ler ublic Resonse a&eResonseitBesseConte>t conte>t, Re@uest re@uest4 t%ro?s *>cetion _`Ob tring ageBae X get/ageBaet4 i# age XX null4 return notoundResonseconte>t, re@uest4 else return a&e/ageResonseconte>t4 _`Od ri6ate tring get/ageBaet conte>t4 t%ro?s *>cetion _`Ob 7i&i/age/at% at% X /at%/arser.arseresource4 /at%/arser.arseresour ce4 cra?ler X conte>t.root.get/ageCra?ler4 cra?ler.set-ead*ndtrateg5ne? irtual*nabled/ageCra?ler44 age X cra?ler.get/ageconte>t.root, at%4 i# age X null4 age-ata X age.get-ata4 _`Od ri6ate Resonse notoundResonseitBesseConte>t conte>t, Re@uest re@uest4 t%ro?s *>cetion _`Ob return ne? BotoundResonder4.a&eResons BotoundResonder4.a&eResonseconte>t, econte>t, re@uest4 _`Od ri6ate ileResonse a&e/ageResonseitBesseConte>t conte>t4 t%ro?s *>cetion _`Ob ageTitle X /at%/arser.rendercra?ler.getull/at%age44 /at%/arser.rendercra?ler.getull/at%age44 tring %tl X a&etlconte>t4
ileResonse resonse X ne? ileResonse4 resonse.setMa>(ge04 resonse.setContent%tl4 return resonse _`Od Y (de=s, este #ragento es un buen e8elo de ubicación de constantes en un ni6el correcto GWU. La constante ront/age se odría %aber ocultado en la #unción get/ageBae
-eterinados concetos de código deben estar ró>ios a otros. Tienen una a#inidad concetual concreta. Cuanto a5or sea esta a#inidad, enor distancia 6ertical debe e>istir entre ellos. Coo %eos 6isto, esta a#inidad se uede basar en una deendencia directa, coo cuando una #unción in6oca a otra, o cuando usa una 6ariable. /ero %a5 otras causas de a#inidad. /uede generarse or@ue un gruo de #unciones realice una oeración siilar. í8ese en este #ragento de código de Junit V.W.: ublic class (ssert _`Ob static ublic 6oid assertTruetring essage, boolean condition4 _`Ob i# condition4 #ailessage4 _`Od static ublic 6oid assertTrueboolean condition4 _`Ob assertTrue null, condition4 _`Od static ublic 6oid assertalsetring essage, boolean condition4 _`Ob assertTrueessage, condition4
_`Od static ublic 6oid assertalseboolean condition4 _`Ob assertalsenull, condition4 _`Od Y *stas #unciones tienen una ele6ada a#inidad concetual 5a @ue coarten un sistea de nobres co;n 5 reali!an 6ariantes de la isa tarea b=sica. *l %ec%o de @ue se in6o@uen unas a otras es secundario. (un@ue no lo %icieran, deberían seguir estando ró>ias entre ellas.
Orden +ertical /or lo general, las deendencias de in6ocaciones de #unciones deben auntar %acia aba8o. *s decir, la #unción in6ocada debe situarse or deba8o de la @ue realice la in6ocación2OU. *sto genera un agradable #lu8o en el código #uente, de los ni6eles sueriores a los in#eriores. Coo sucede en los artículos del eriódico, eseraos @ue los concetos =s iortantes aare!can antes 5 @ue se e>resen con la enor cantidad de detalles sobrantes. *seraos @ue los detalles de ni6el in#erior sean los ;ltios. -e este odo, odeos o8ear los arc%i6os de código 5 catar el ensa8e en las rieras #unciones sin necesidad de suergios en los detalles. *l Listado 1 se organi!a de esta #ora. /uede @ue otros e8elos e8ores sean los listados . 5 W.O.
$ormato /orizontal HKué anc%o debe tener una líneaI /ara resonderlo, #í8ese en la anc%ura de las líneas de un rograa con6encional. -e nue6o, e>ainaos siete ro5ectos di#erentes. *n la #igura .2 uede 6er la distribución de longitud de todos ellos. La regularidad es iresionante, en esecial en too a los V caracteres. -e %ec%o, los taa3os entre 20 5 N0 reresentan un uno or den del n;ero total de líneas. f*so es un V0 or 00 /uede @ue otro W0 or 00 sea enos de 0 caracteres de anc%o. Recuerde @ue es una escala de registro, de odo @ue la aariencia lineal es u5 signi#icati6a. *s e6idente @ue los rograadores re#ieren líneas enos anc%as.
igura .2. -istribución de anc%ura de líneas en Ja6a. *sto sugiere @ue debeos intentar reducir las líneas de código. *l antiguo líite ollerit% de A0 es un tanto arbitrario 5 no e oongo a líneas @ue tienen 00 o incluso 20, ero no =s. Coo nora, no debe tener @ue desla!arse %acia la derec%a. Los onitores odernos son =s anc%os 5 los rograadores no6eles ueden reducir la #uente ara enca8ar %asta 200 caracteres en la antalla. Bo lo %aga. Mi líite ersonal es de 20.
Apertura - densidad /orizontal saos el esacio en blanco %ori!ontal ara asociar eleentos directaente relacionados 5 searar otros con una relación enos estrec%a. í8ese en la siguiente #unción: ri6ate 6oid easureLinetring line4 _`Ob lineCountZZ int linei!e X line.lengt%4 totalC%ars ZX linei!e line7idt%istogra.addLinelinei!e, lineCount4 record7idestLinelinei!e4 _`Od eos rodeado los oeradores de asignación con esacios en blanco ara destacarlos. Las instrucciones de asignación tienen dos eleentos rinciales: el lado i!@uierdo 5 el derec%o. Los esacios acent;an esta searación. /or otra arte, no %eos incluido esacios entre los nobres de las #unciones 5 el aréntesis de aertura, 5a @ue la #unción 5 sus arguentos est=n estrec%aente estrec% aente relacionados. u searación los desconectaría. earo los arguentos en los aréntesis de in6ocación de la #unción ara acentuar la coa e indicar @ue los arguentos son indeendientes. *l esacio en blanco tabién se usa ara acentuar la recedencia de los
oeradores: ublic class Kuadratic _`Ob ublic static double rootdouble a, double b, double c4 _`Ob double deterinant X deterinanta, b, c4 return 1b Z Mat%.s@rtdeterinant44 Q 2a4 _`Od ublic static double root2int a, int b, int c4 _`Ob double deterinant X deterinanta, b, c4 return 1b 1 Mat%.s@rtdeterinant44 Q 2a4 _`Od ri6ate static double deterinantdouble a, double b, double c4 _`Ob return bb 1 Vac _`Od _`Od í8ese en lo bien @ue se leen las ecuaciones. Los #actores carecen de esacios en blanco 5a @ue tienen una a5or recedencia. reced encia. Los térinos se searan ediante esacios esa cios en blanco 5a @ue la sua 5 la resta son de recedencia recedencia in#erior. -esa#ortunadaente, uc%as %erraientas de #orato de código ignoran la recedencia de los oeradores e ionen un esaciado uni#ore. /or ello, e llo, searaciones sutiles coo las anteriores suelen erderse tras odi#icar el #orato del código.
Alineación /orizontal Cuando era rograador de lengua8es de ensablado2AU, usaba la alineación %ori!ontal ara acentuar deterinadas estructuras. Cuando coencé a rograar en C, CZZ 5 Ja6a, seguía intentando alinear los nobres de 6ariables en un con8unto de declaraciones o todos los 6alores en un gruo de instrucciones de asignación. *l asecto de i código era el siguiente: ublic class itBesse*>editer ileents Resonseender _`Ob ri6ate oc&et soc&et ri6ate "nuttrea inut ri6ate t conte>t rotected long re@uest/arsingTieLiit ri6ate long re@uest/rogress ri6ate long re@uest/arsing-eadline ri6ate boolean %as*rror ublic itBesse*>editer oc&et s, itBesseConte>t conte>t4 t%ro?s *>cetion _`Ob t%is.conte>t X conte>t soc&et X s inut X s.get"nuttrea4 outut X s.gettensas @ue deben alinearse, el roblea es la longitud de las listas, no la #alta de alineación. La longitud de la siguiente lista de declaraciones de itBesse*>editer sugiere @ue esta clase debe di6idirse. ublic class itBesse*>editer ileents Resonseender
_`Ob ri6ate oc&et soc&et ri6ate "nuttrea inut ri6ate t conte>t rotected long re@uest/arsingTieLiit ri6ate long re@uest /rogress ri6ate long re@uest/arsing-eadline ri6ate boolean %as*rror ublic itBesse*>editeroc&et s, itBesseConte>t conte>t4 t%ro?s *>cetion _`Ob t%is.conte>t X conte>t soc&et X s inut X s.get"nuttrea4 outut X s.get
Sangrado n arc%i6o de código es una 8erar@uía =s @ue un contorno. "nclu5e in#oración @ue ertenece a la totalidad del arc%i6o, a sus clases indi6iduales, a los étodos de las clases, a los blo@ues de los étodos 5 a los blo@ues de los blo@ues. Cada ni6el de esta 8erar@uía es un =bito en el @ue se ueden declarar nobres 5 en el @ue se interretan interr etan declaraciones e instrucciones e8ecutables. /ara @ue esta 8erar@uía de =bitos sea 6isible, sangraos las líneas de código #uente de acuerdo a su osición en la 8erar@uía. Las instrucciones al ni6el del arc%i6o, coo las declaraciones de clases, no se sangran. Los étodos de una clase se sangran un ni6el a la derec%a de la clase. Las ileentaciones de dic%os étodos se ileentan un ni6el a la derec%a de la declaración de los étodos. Las ileentaciones de blo@ues se ileentan un ni6el a la derec%a de su blo@ue contenedor 5 así sucesi6aente. Los rograadores deenden de este sistea de sangrado. (linean 6isualente las líneas a la i!@uierda ara 6er el =bito al @ue ertenece. -e este odo ueden acceder r=idaente a los =bitos, coo or e8elo a ileentaciones de instrucciones i# o ?%ile, @ue no son rele6antes ara la situación actual. )uscan en la i!@uierda nue6as declaraciones de étodos, 6ariables e incluso clases. in el sangrado, los rograas serian r=cticaente ilegibles. í8ese en los siguientes rograas, sint=ctica 5 se=nticaente idénticos: ublic class itBesseer6er ileents oc&eter6er _`Ob ri6ate itBesseConte>t conte>t ublic itBesseer6eritBesseConte>t conte>t4 _`Ob t%is.conte>t X conte>t _`Od ublic 6oid ser6eoc&et s4 _`Ob ser6es, 00004 _`Od ublic 6oid ser6eoc&et s, long re@uestTieout4 _`Ob tr5 _`Ob itBesse*>editer sender X ne? itBesse*>editers, conte>t4 sender.setRe@uest/arsingTieLiitre@uestTieout4 sender.start4 _`Od
catc%*>cetion e4 _`Ob e.rinttac&Trace4 _`Od _`Od _`Od ublic class itBesseer6er ileents oc&eter6er _`Ob ri6ate itBesseConte>t conte>t ublic itBesseer6eritBesseConte>t conte>t4 _`Ob t%is.conte>t X conte>t _`Od ublic 6oid ser6eoc&et s4 _`Ob ser6e s, 00004 _`Od ublic 6oid ser6eoc&et s, long re@uestTieout4 _`Ob tr5 _`Ob itBesse*>editer sender X ne? itBesse*>editers, conte>t4 sender.setRe@uest/arsingTieLiitre@uestTieout4 sender.start 4 _`Od catc% *>cetion e4 _`Ob e.rinttac&Trace4 _`Od _`Od _`Od ( la 6ista uede incluso areciar la estructura del arc%i6o sangrado. -etectaos inediataente las 6ariables, constructores 5 étodos de acceso. *n cuestión de segundos 6eos @ue es una esecie de inter#a! de cone>ión, con un tieo de esera. La 6ersión sin sangrar, or su arte, es r=cticaente ienetrable. 4omper el sangrado *n ocasiones teneos la tentación de roer la regla de sangrado con instrucciones i# bre6es, bucles ?%ile bre6es o #unciones bre6es. iere @ue %e sucubido a esta tentación, %e acabado or 6ol6er a alicar el sangrado. /or ello, e6ito relegar =bitos a una línea, coo en este e8elo: ublic class Coent7idget e>tends Te>t7idget _`Ob ublic static #inal tring R*G*+/ X jkj_r_nUI:I:_r_n4_n_r4I ublic Coent7idget/arent7idget arent, tring te>t4_`Obsuer arent, te>t4_`Od ublic tring render4 t%ro?s *>cetion _`Ob return _`Od _`Od /re#iero deslegar 5 sangrar los =bitos: ublic class Coent7idget e>tends Te>t7idget _`Ob ublic static #inal tring R*G*+/ X jkj_r_nUI:I:_r_n4_n_r4I ublic Coent7idget/arent7idget arent, tring te>t4 _`Ob suerarent, te>t4 _`Od ublic tring render4 t%ro?s *>cetion _`Ob return _`Od
_`Od
[mbitos ficticios *n ocasiones, el cuero de una instrucción ?%ile o #or es #icticio, coo se uestra a continuación. Bo e gustan estas estructuras 5 re#iero e6itarlas. *n caso de no oder %acerlo, e aseguro de sangrar el cuero #icticio 5 de incluirlo entre aréntesis. Bo sabría decir cu=ntas 6eces e %a enga3ado un unto 5 coa situado al #inal de un bucle ?%ile en la isa línea. ( enos @ue lo %aga 6isible 5 lo sangre en una línea roia, es di#ícil de 6er. ?%ile dis.readbu#, 0, read)u##eri!e4 X 14
4eglas de e9uipo
Todo rograador tiene sus reglas de #orato re#eridas, ero si #ora arte de un e@uio, el e@uio anda. n e@uio de rograadores debe acordar un ;nico estilo de #orato 5 todos los integrantes del e@uio deben alicarlo. *l ob8eti6o es @ue el software tenga un estilo co%erente. Bo @uereos @ue are!ca escrito or indi6iduos en#rentados. Cuando coencé el ro5ecto itBesse en 2002, e reuní con el e@uio ara de#inir un estilo de código. Tardaos 0 inutos. -ecidios dónde a3adir las lla6es, @ué taa3o de sangrado utili!ar, los nobres de clases, 6ariables 5 étodos, 5 de=s. Tras ello, codi#icaos las reglas en el "-* 5 las culios desde entonces. Bo son las reglas @ue re#iero, son las @ue el e@uio decidió. E coo co o iebro de ese e@uio, las ali@ue cuando creaos el código del ro5ecto itBesse. Recuerde @ue un buen sistea de software se coone de una serie de docuentos @ue se leen #=cilente. -eben tener un estilo co%erente 5 din=ico. *l lector debe con#iar en @ue los #oratos @ue 6e en nuestro arc%i6o de código signi#icar=n lo iso ara otros. Lo ;ltio @ue @uereos es auentar la cole8idad del código creando una e!cla de estilos di#erentes.
4eglas de formato de 8ncle (ob Las reglas @ue uso ersonalente son sencillas 5 se ilustran en el código del Listado 1N. Considérelo un e8elo de docuento est=ndar de código ótio. !istado FL
Code(nal5!er.8a6a. ublic class Code(nal5!er ileents Ja6aile(nal5sis _`Ob ri6ate int lineCount ri6ate int a>Line7idt% ri6ate int ?idestLineBuber ri6ate Line7idt%istogra line7idt%istogra ri6ate int totalC%ars ublic Code(nal5!er4 _`Ob line7idt%istogra X ne? Line7idt%istogra4 _`Od ublic static List]ile^ #indJa6ailesile arent-irector54 _`Ob List]ile^ #iles X ne? (rra5List]ile^4 #indJa6ailesarent-irector5, #iles4 return #iles _`Od ri6ate static 6oid #indJa6ailesile arent-irector5, List]ile^ #iles4 _`Ob #or ile #ile : arent-irector5.listiles44 _`Ob i# #ile.getBae4.ends7it%.8a6a44 #iles.add#ile4 else i# #ile.is-irector544 #indJa6ailes#ile, #iles4 _`Od _`Od ublic 6oid anal5!eileile 8a6aile4 t%ro?s *>cetion _`Ob )u##eredReader br X ne? )u##eredReaderne? ileReader8a6aile44 tring line ?%ile line X br.readLine44 X null4 easureLineline4 _`Od ri6ate 6oid easureLinetring line4 _`Ob lineCountZZ int linei!e X line.lengt%4 totalC%ars ZX linei!e line7idt%istogra.addLinelinei!e, lineCount4 record7idestLinelinei!e4 _`Od ri6ate 6oid record7idestLineint linei!e4 _`Ob i# linei!e ^ a>Line7idt%4 _`Ob a>Line7idt% X linei!e
?idestLineBuber X lineCount _`Od _`Od ublic int getLineCount4 _`Ob return lineCount _`Od ublic int getMa>Line7idt%4 _`Ob return a>Line7idt% _`Od ublic int get7idestLineBuber4 _`Ob return ?idestLineBuber _`Od ublic Line7idt%istogra getLine7idt%istogra4 _`Ob return line7idt%istogra _`Od ublic double getMeanLine7idt%4 _`Ob return double4totalC%arsQlineCount _`Od ublic int getMedianLine7idt%4 _`Ob "ntegerU sorted?idt%s X getorted7idt%s4 int cuulati6eLineCount X 0 #or int ?idt% : sorted?idt%s4 _`Ob cuulati6eLineCount ZX lineCountor7idt%?idt%4 i# cuulati6eLineCount ^ lineCountQ24 return ?idt% _`Od t%ro? ne? *rror Cannot get %ere4 _`Od ri6ate int lineCountor7idt%int ?idt%4 _`Ob return line7idt%istogra.getLines#or7idt%?idt%4.si!e4 _`Od ri6ate "ntegerU getorted7idt%s4 _`Ob et]"nteger^ ?idt%s X line7idt%istogra.get7idt%s4 "ntegerU sorted?idt%s X ?idt%s.to(rra5ne? "nteger0U44 (rra5s.sortsorted?idt%s4 return sorted?idt%s _`Od _`Od
L Ob)etos - estructuras de datos
a5 una ra!ón ara @ue las 6ariables sean ri6adas. Bo @uereos @ue nadie =s deenda de ellas. Kuereos oder cabiar su tio o ileentación cuando deseeos. *ntonces, Hor @ué tantos rograadores a3aden auto=ticaente étodos de estableciiento 5 recueración @ue uestran sus 6ariables ri6adas coo si #ueran ;blicasI
Abstracción de datos í8ese en la di#erencia entre los listados N. 5 N.2. (bos reresentan los datos de un unto cartesiano, ero uno uestra su ileentación 5 otro la oculta totalente. !istado LF
/unto concreto. ublic class /oint _`Ob ublic double > ublic double 5 _`Od !istado LF
/unto abstracto. ublic inter#ace /oint _`Ob double get+4 double getE4 6oid setCartesiandouble >, double 54 double getR4 double getT%eta4 6oid set /olardouble r, double t%eta4 _`Od Lo e8or del Listado N12 es @ue no %a5 #ora de saber si la ileentación est= en coordenadas rectangulares o olares. f/uede @ue en ninguna E aun así la inter#a! reresenta sin lugar a dudas una estructura de datos. /ero reresenta algo =s @ue una estructura de datos. Los étodos re#uer!an una olítica de acceso. /uede leer las coordenadas coordenad as de #ora indeendiente, ero debe de be establecerlas de #ora con8unta coo oeración atóica. *l Listado N1, or su arte, se ileenta claraente en coordenadas rectangulares 5 nos obliga a aniularlas de #ora indeendiente, lo @ue uestra la ileentación. -e %ec%o, la ostraría igualente, aun@ue las 6ariables #ueran ri6adas 5 us=raos étodos 6ariables de estableciiento 5 recueración. /ara ocultar la ileentación no basta con a3adir una caa de #unciones entre las 6ariables. e basa en la abstracción. na clase no #uer!a sus 6ariables a tra6és de étodos de estableciiento 5 recueración. /or el contrario, uestra inter#aces abstractas @ue eriten a sus usuarios aniular la esencia de los datos sin necesidad de conocer su ileentación. í8ese en los listados N.W 5 N.V. *l riero usa térinos concretos ara indicar el ni6el de cobustible de un 6e%ículo ientras @ue el segundo lo %ace con la abstracción del orcenta8e. *n el caso concreto, odeos ode os estar seguros de @ue se trata de d e étodos de acceso de 6ariables. *n el caso abstracto, desconoceos la #ora de los datos. !istado LFG
e%ículo concreto. ublic inter#ace e%icle _`Ob double getuelTan&Caacit5"nGallons4 double getGallons<#Gasoline4 _`Od !istado LF e%ículo abstracto. ublic inter#ace e%icle _`Ob double get/ercentuelReaining4
_`Od *n abos casos, la segunda oción es re#erible. Bo @uereos ostrar los detalles de los datos, sino e>resarlos en térinos abstractos. *sto no se consigue sileente ediante inter#aces o étodos de estableciiento 5 recueración. a5 @ue editar seriaente la #ora ótia de reresentar los datos @ue contiene un ob8eto. La eor oción es a3adir étodos de estableciiento 5 recueración a ciegas.
Antisimetr:a de datos - ob)etos *stos dos e8elos ilustran la di#erencia entre ob8etos 5 estructuras de datos. Los ob8etos ocultan sus datos tras abstracciones 5 uestran #unciones @ue oeran en dic%os datos. La estructura de datos uestra sus datos 5 carece de #unciones con signi#icado. uel6a a leerlos. í8ese en la naturale!a coleentaria de las dos de#iniciones. on 6irtualente ouestas. /uede arecer una di#erencia enor, ero tiene iortantes ilicaciones. í8ese en el e8elo del Listado N1. La clase Geoetr5 oera en las tres clases de #oras, @ue son sencillas estructuras de datos sin coortaiento. Todo el coortaiento se encuentra en la clase Geoetr5. !istado LF
ora ediante rocediientos. ublic class @uare _`Ob ublic /oint toLe#t ublic double side _`Od ublic class Rectangle _`Ob ublic /oint toLe#t ublic double %eig%t ublic double ?idt% _`Od ublic class Circle _`Ob ublic /oint center ublic double radius _`Od ublic class Geoetr5 _`Ob ublic #inal double /" X W.V92NWA9O9W ublic double areacetion _`Ob i# s%ae instanceo# @uare4 _`Ob @uare s X @uare4s%ae return s.side s.side _`Od else i# s%ae instanceo# Rectangle4 _`Ob Rectangle r X Rectangle4s%ae return r.%eig%t r.?idt% _`Od
else i# s%ae instanceo# Circle4 _`Ob Circle c X Circle4s%ae return /" c.radius c.radius _`Od t%ro? ne? Bouc%%ae*>cetion4 _`Od _`Od Los rograadores orientados a ob8etos se @ue8ar=n de @ue es un e8elo de rocediiento, 5 tienen ra!ón. "agine @ué asaría as aría si a3adios la #unción erieter4 a Geoetr5. fLas clases de #oras no se 6erían a#ectadas fE las de=s clases @ue deendieran de las #oras taoco /or otra arte, si a3ado una nue6a #ora, tendría @ue cabiar todas las #unciones de Geoetr5. uél6alo a leer. Corobar= @ue las dos condiciones son diaetralente ouestas. í8ese a%ora en la solución orientada a ob8etos del Listado N1N. (@uí, el étodo area4 es oliór#ico. Bo se necesita una clase Geoetr5. /or tanto, si a3ado una nue6a #ora, ninguna de las #unciones e>istentes se 6en a#ectadas, ero si a3ado otra #unción, %abr= @ue cabiar todas las #oras29U. !istado LFL oras oliór#icas. ublic class @uare ileents %ae _`Ob ri6ate /oint toLe#t ri6ate double side ublic double area4 _`Ob return sideside _`Od ublic class Rectangle ileents %ae _`Ob ri6ate /oint toLe#t ri6ate double %eig%t ri6ate double ?idt% ublic double area4 _`Ob return %eig%t ?idt% _`Od _`Od ublic class Circle ileents %ae _`Ob ri6ate /oint center ri6ate double radius ublic #inal double /" X W.V92NWA9O9W ublic double area4 _`Ob return /" radius radius _`Od _`Od -e nue6o, 6eos la naturale!a coleentaria de estas dos de#iniciones totalente contrarias. *sto ilustra la dicotoía #undaental entre ob8etos 5 estructuras de datos: )l c2digo por procedimientos Hel *%e %sa estr%ct%ras de datosI facilita facilita la incl%si2n de n%evas f%nciones sin modificar las estr%ct%ras de da tos e9istentes" )l c2digo orientado
a ob0etos, por s% parte, facilita la incl%si2n de n%evas clases sin cambiar las f%nciones e9istentes"
*l coleento tabién es cierto: )l c2digo por procedimientos dific%lta la incl%si2n de n%evas estr%ct%ras de datos .a *%e es necesario cambiar todas las f%nciones" )l c2digo orientado a ob0etos dific%lta la incl%si2n de n%evas f%nciones .a *%e es necesario cambiar todas las clases"
/or tanto, lo @ue es di#ícil ara la rograación orientada a ob8etos es #=cil ara los rocediientos, 5 6ice6ersa. *n cual@uier sistea cole8o %abr= ocasiones en las @ue @ueraos a3adir nue6os tios de datos en lugar de nue6as #unciones. *n dic%os casos, los ob8etos 5 la rograación orientada a ob8etos es lo =s adecuado. /or otra arte, en ocasiones tendreos @ue a3adir nue6as #unciones en lugar de tios de datos, ara lo @ue resulta =s adecuado usar código or rocediientos 5 estructuras de datos. d atos. Los rograadores e>erientados saben @ue la idea de @ue todo es un ob8eto es un ito. *n ocasiones solaente *%eremos sencillas estructuras de datos con rocediientos @ue oeren en las isas.
!a le- de 2emeter *>iste una conocida %eurística denoinada 'e. de Demeter W0U @ue a#ira @ue un ódulo no debe conocer los entresi8os de los ob8etos @ue aniula. Coo 6ios en el aartado anterior, los ob8etos ocultan sus datos 5 uestran oeraciones, lo @ue signi#ica @ue un ob8eto no debe ostrar su estructura interna a tra6és de étodos de acceso 5a @ue, si lo %ace, ostraría, no ocultaría, su estructura interna. *n concreto, la le5 de -eeter a#ira @ue un étodo de una clase C sólo sólo debe in6ocar los étodos de: C . n ob8eto creado or f . n ob8eto asado coo arguento a f . n ob8eto en una 6ariable de instancia de C . *l étodo no debe in6ocar étodos de ob8etos de6ueltos or ninguna de las #unciones eritidas. *s decir, no %able con desconocidos, sólo con aigos. *l siguiente códigoWU arece inculir la Le5 de -eeter entre otras cosas4 5a @ue in6oca la #unción getcratc%-ir4 en el 6alor de6uelto de get<tions4 5 desués in6oca get(bsolute/at%4 en el 6alor de6uelto de getcratc%-ir4. #inal tring outut-ir X ct>t.get<tions4.getcratc%-ir4.get(bsolute/at%4
C/o9ue de trenes *se tio de código suele denoinarse c%o@ue de trenes 5a @ue se asee8a a un gruo de 6agones de tren. *stas cadenas de in6ocaciones suelen considerarse un estilo descuidado 5 deben e6itarse GWNU. Con6iene di6idirlas de esta #ora: <tions ots X ct>t.get<tions4 ile scratc%-ir X ots.getcratc%-ir4
#inal tring outut-ir X scratc%-ir.get(bsolute/at%4
H"nculen estos dos #ragentos de código la Le5 de -eeterI in duda el ódulo contenedor sabe @ue el ob8eto ct>t contiene ociones, @ue contienen un directorio scratc%, @ue tiene una ruta absoluta. La #unción sabe deasiado. La #unción @ue reali!a la in6ocación sabe cóo desla!arse or nuerosos ob8etos di#erentes. i incule o no la Le5 de -eeter deende de si ct>t, <tions 5 cratc%-ir son ob8etos o estructuras de datos. i son ob8etos, debería ocultarse su estructura interna, no ostrarse, 5 conocer sus detalles internos sería un claro inculiiento de la Le5 de -eeter. /or otra arte, si ct>t, <tions 5 cratc%-ir son siles estructuras de datos, ostrar=n su estructura interna con naturalidad 5 la Le5 de -eeter no se alica. *l uso de #unciones de acceso colica el roblea. i el código se %ubiera escrito de esta otra #ora, robableente no nos reocuaríaos de si se incule la Le5 de -eeter o no. #inal tring outut-ir X ct>t.otions.cratc%-ir.absolute/at% *l roblea sería enos con#uso si las estructuras de datos tu6ieran 6ariables ;blicas 5 no #unciones, 5 los ob8etos tu6ieran 6ariables ri6adas 5 #unciones ;blicas. in in ebargo, e>isten estructuras 5 est=ndares coo los bean4 @ue e>igen @ue incluso una sencilla estructura de datos tenga eleentos de acceso 5 utación.
":bridos *sta con#usión genera ocasionalente desa#ortunadas estructuras %íbridas itad ob8eto 5 itad estructura de datos. Tienen #unciones @ue reali!an tareas signi#icati6as 5 tabién 6ariables ;blicas o étodo ;blicos de acceso 5 utación @ue %acen @ue las 6ariables ri6adas sean ;blicas, 5 tientan a otras #unciones e>ternas a usar dic%as 6ariables de la isa #ora @ue un rograa or rocediientos usaría una estructura de datosW2U. *stos %íbridos di#icultan la inclusión de nue6as #unciones 5 tabién de nue6as estructuras de datos. on lo eor de abos undos. *6ítelos. "ndican un dise3o descuidado cu5os autores dudan, o eor toda6ía, desconocen, si necesitan rotegerse de #unciones o tios.
Ocultar la estructura HKué asaría si ct>t, otions 5 scratc%-ir #ueran ob8etos con un coortaiento realI Coo los ob8etos deben ocultar su estructura interna, no odríaos desla!aos or
los isos. *ntonces, Hcóo obtendríaos la ruta absoluta del directorio scratc%I ct>t.get(bsolute/at%<#cratc%-irector5<tion4 o ct>.getcratc%-irector5<tion4.get(bsolute/at%4 La riera oción ro6ocaría una e>losión de étodos en el ob8eto ct>t. La segunda asue @ue getcratc%-irector5<tion4 de6uel6e una estructura de datos, no un ob8eto. Binguna de las ociones arece correcta. i ct>t es un ob8eto, deberíaos indicarle @ue %iciera algo, no reguntar sobre sus detalles internos. *ntonces, Hara @ué @uereos la ruta absoluta del directorio scratc%I HCóo 6aos a usarlaI í8ese en este código del iso ódulo uc%as líneas desués4: tring outile X outut-ir Z Q Z classBae.relacem.h, mQh4 Z .class iletensiones de arc%i6o 5 ob8etos ile no deben e!clarse de esta #ora, 8unto al código contenedor. i lo ignoraos, 6eos @ue la intención de obtener la ruta absoluta del directorio scratc% es crear un arc%i6o de borrador de un nobre concreto. HE si le di8éraos al ob8eto ct>t @ue %iciera estoI )u##eredt.createcratc%iletrea.classileBae4 /arece algo ra!onable ara un ob8eto. /erite a ct>t ocultar sus detalles internos e iide @ue la #unción actual incula la Le5 de -eeter 5 se deslace or ob8etos @ue no debería conocer.
Ob)etos de transferencia de datos La @uintaesencia de una estructura de datos es una clase con 6ariables ;blicas 5 sin #unciones. *n ocasiones se denoina iones, etc. uelen ser los rieros de d e una serie de #ases de traducción @ue con6ierten datos sin rocesar en ob8etos en el código de la alicación. M=s co;n es la #ora de bean ostrada en el Listado N1O. Los bean tienen 6ariables ri6adas aniuladas or étodos de estableciiento 5 recueración. La cuasi1 *ncasulación de bean %ace @ue algunos uristas de la rograación orientada a ob8etos se sientan e8or ero no o#rece ning;n otro bene#icio. !istado LF=
address.8a6a ublic class (ddress _`Ob ri6ate tring street ri6ate tring street*>tra ri6ate tring cit5 ri6ate tring state ri6ate tring !i ublic (ddresstring treet, tring street*>tra, tring cit5, tring state, tring !i4 _`Ob t%is.street X street
t%is.street*>tra X street*>tra t%is.cit5 X cit5 t%is.state X state t%is.!i X !i _`Od ublic tring gettreet4 _`Ob return street _`Od ublic tring gettreet*>tra4 _`Ob return street*>tra _`Od ublic tring getCit54 _`Ob return cit5 _`Od ublic tring gettate4 _`Ob return gettate _`Od ublic tring getDi4 _`Ob return !i _`Od _`Od
4egistro acti+o Los registros acti6os son una #ora esecial de tra3o 5a @ue crea un %ibrido entre una estructura de datos 5 un ob8eto. La solución, e6identeente, consiste en considerar al registro acti6o una estructura de datos 5 crear ob8etos indeendientes @ue contengan las reglas eresariales 5 @ue oculten sus datos internos @ue robableente sean instancias del roio registro acti6o4.
Conclusión Los ob8etos uestran coortaiento 5 ocultan datos. *sto #acilita la inclusión de nue6os tios de ob8etos sin necesidad de cabiar los coortaientos e>istentes. Tabién di#iculta la inclusión de nue6os coortaientos en ob8etos e>istentes. Las estructuras de datos uestran datos 5 carecen de coortaiento signi#icati6o. *sto #acilita la inclusión de nue6os coortaientos en las estructuras de datos e>istentes, ero di#iculta la inclusión de nue6as estructuras de datos en #unciones e>istentes. *n un sistea, en ocasiones necesitareos la #le>ibilidad de a3adir nue6os tios de datos, or lo @ue re#erios ob8etos ara esa arte del sistea. *n otros casos, @uerreos a3adir nue6os coortaientos, ara lo @ue re#erios tios de datos 5 rocediientos en
esa arte del sistea. Los buenos rograadores de software entienden estos robleas sin re8uicios 5 eligen el en#o@ue =s adecuado ara a ra cada tarea concreta.
(ibliograf:a ;4efactoring>: efactoring: 3mproving the Design of )9isting Code, Martin o?ler et al., (ddison17esle5, 999.
= Procesar errores or Mic%ael eat%ers
Le arecer= e>tra3o encontrar una sección de control de errores en un libro sobre código liio. *l control de errores es algo @ue todos teneos @ue %acer al rograar. Las entradas ueden ser incorrectas 5 los disositi6os ueden #allar, 5 cuando lo %acen, los rograadores soos resonsables res onsables de corobar @ue el código %ace lo @ue debe %acer. Bo obstante, la cone>ión con el código liio debe ser e6idente. Muc%as bases de código est=n totalente doinadas or el control de errores. Cuando digo @ue est=n doinadas, no @uiero decir @ue ;nicaente realicen control de código, sino @ue es r=cticaente iosible 6er lo @ue el código %ace debido a todo ese control de errores. *l control de errores es iortante, pero si osc%rece la l2gica, es incorrecto. *n este caítulo detallareos di6ersas técnicas 5 consideraciones @ue uede usar ara crear código liio 5 robusto, código @ue rocese los errores con elegancia 5 estilo.
8sar eEcepciones en lugar de códigos de+ueltos *n el asado, uc%os lengua8es carecían de e>ceciones. Las técnicas ara rocesar e in#orar de errores eran liitadas. e de#inía un indicador de error o se de6ol6ía un código de error @ue el in6ocador odía corobar. *l código del Listado O1 ilustra estos en#o@ues. !istado =F
-e6iceController.8a6a. ublic class -e6iceController _`Ob Y ublic 6oid send%ut-o?n4 _`Ob
-e6iceandle %andle X getandle-*4 QQ Corobar el estado del disositi6o i# %andle X -e6iceandle."B(L"-4 _`Ob QQ Guardar el estado del disositi6o en el cao de registro retrie6e-e6iceRecord%andle4 QQ i no est= susendido, cerrarlo i# _`Ob record.gettatus4 X -*"C*/*B-*-4 _`Ob ause-e6ice%andle4 clear-e6ice7or&Kueue%andle4 close-e6ice%andle4 _`Od else _`Ob logger.log-e6ice susended. nable to s%ut do?n4 _`Od _`Od else _`Ob logger.log"n6alid %andle #or: Z -*.totring44 _`Od _`Od Y _`Od *l roblea de estos en#o@ues es @ue con#unden al in6ocador. *l in6ocador debe corobar inediataente los errores desués de la in6ocación. -esa#ortunadaente, es algo @ue se suele ol6idar. /or ello, es =s recoendable generar una e>ceción al detectar un error. *l código de in6ocación es =s liio. u lógica no se oscurece or el control de errores. *l Listado O12 uestra el código tras generar una e>ceción en los étodos @ue ueden detectar errores. !istado =F
-e6iceController.8a6a con e>ceciones4. ublic class -e6iceController _`Ob Y ublic 6oid send%ut-o?n4 _`Ob tr5 _`Ob tr5To%ut-o?n4 _`Od catc% -e6ice%ut-o?n*rror e4 _`Ob logger.loge4 _`Od _`Od ri6ate 6oid tr5To%ut-o?n4 t%ro?s -e6ice%ut-o?n*rror _`Ob -e6iceandle %andle X getandle-*4 -e6iceRecord record X retrie6e-e6iceRecord%andle4 ause-e6ice%andle4 clear-e6ice7or&Kueue%andle4 close-e6ice%andle4 _`Od ri6ate -e6iceandle getandle-e6icel- id4 _`Ob Y
t%ro? ne? -e6ice%ut-o?n*rror"n6alid %andle #or: 1 id.totring44 Y _`Od Y _`Od Corobar= @ue es uc%o =s liio. Bo es cuestión de estética. *l código es e8or or@ue se sol6entan dos reocuaciones: el algorito ara aagar el disositi6o 5 el control de errores a%ora se encuentran searados. /uede 6er cada uno de ellos 5 entenderlos de #ora indeendiente.
Crear primero la instrucción tr-Fcatc/Ffinallno de los asectos =s interesantes de las e>ceciones es @ue definen %n #mbito en el rograa. (l e8ecutar código en la arte tr5 de una instrucción tr51catc%1#inall5, indicaos @ue la e8ecución se uede cancelar en cual@uier oento 5 desués retoar en catc%. Los blo@ues tr5 son coo las transacciones, catc% debe salir del rograa en un estado co%erente, indeendienteente de lo @ue suceda en tr5. /or este oti6o, es aconse8able iniciar con una instrucción tr51catc%1#inall5 el código @ue genere e>ceciones. -e este odo de#ine lo @ue debe eserar el usuario del código, indeendienteente de se rodu!ca un error en el e l código e8ecutado en la cl=usula tr5. eaos un e8elo. "agine @ue tiene @ue crear un código @ue acceda a un arc%i6o 5 lea ob8etos seriali!ados. Coen!aos con una rueba de unidad @ue uestra @ue obtendreos una e>ceción cuando el arc%i6o no e>ista: [Teste>ected X torage*>cetion.class4 ublic 6oid retrie6eection%ouldT%ro?ceción. Tras ello, cabiaos la ileentación ara @ue intente acceder a un arc%i6o no 6=lido. *sta oeración genera una e>ceción: ublic List]RecordedGri^ retrie6eection tring sectionBae4 _`Ob tr5 _`Ob ile"nutstrea strea X ne? ile"nuttreasectionBae4 _`Od catc% *>cetion e4 _`Ob t%ro? ne? torage*>cetionretrie6al error, e4 _`Od return ne? (rra5List]RecordedGri^4 _`Od (%ora la rueba es correcta 5a @ue caturaos la e>ceción 5 5a odeos
re#actori!ar. /odeos reducir el tio de la e>ceción caturada ara @ue coincida con el tio generado desde el constructor ile"nuttrea: ileBotound*>cetion: ublic List]RecordedGri^ retrie6eectiontring sectionBae4 _`Ob tr5 _`Ob ile"nuttrea strea X ne? ile"nuttreasectionBae4 strea.close4 _`Od catc% ileBotound*>cetion e4 _`Ob t%ro? ne? torage*>cetionretrie6al error, e4 _`Od return ne? (rra5List]RecordedGri^4 _`Od (%ora @ue %eos de#inido el =bito con una estructura tr51catc%, odeos usar T-- ara dise3ar el resto de la lógica necesaria. -ic%a lógica se a3ade entre la creación de ile"nuttrea 5 el cierre, 5 odeos retender @ue no asa nada incorrecto. "ntente crear ruebas @ue #uercen las e>ceciones, ara desués a3adir al controlador un coortaiento @ue satis#aga dic%as ruebas. -e este odo riero crear= el =bito de transacción del blo@ue tr5 5 odr= antener la naturale!a de transacción del =bito.
8sar eEcepciones sin comprobar *l debate %a terinado. -urante a3os, los rograadores de Ja6a %an debatido las 6enta8as 5 los robleas de las e>ceciones corobadas. Cuando aarecieron en la riera 6ersión de Ja6a, arecían are cían una gran idea. La #ira de todos los étodos enueraría todas las e>ceciones @ue se odían asar a su in6ocador. *s =s, estas e>ceciones #oraban arte del tio del étodo. *l código no se coilaría si la #ira no coincidía con lo @ue el código iba a %acer. *n a@uel oento, ens=baos @ue las e>ceciones corobadas eran una gran idea 5 sí, o#recían ciertas 6enta8as. in ebargo, a%ora es e6idente @ue no se necesitan ara crear software robusto. Ck carece de e>ceciones corobadas 5, a esar de los intentos, CZZ taoco, coo sucede en /5t%on o Rub5. E en todos estos lengua8es se uede crear software robusto. /or ello, debeos decidir si las e>ceciones corobadas 6alen su recio. HKué recioI *l recio de las e>ceciones corobadas es un inculiiento del rinciio abiertoQcerradoWWU. i genera una e>ceción corobada desde un étodo de su código 5 la cl=usula catc% se encuentra tres ni6eles or deba8o, debe declarar dic%a e>ceción en la #ira de todos los étodos corendidos entre su osición 5 catc%. *sto signi#ica @ue un cabio en un ni6el in#erior del software uede #or!ar cabios de #ira en uc%os ni6eles sueriores. er= necesario 6ol6er a generar e ileentar los ódulos cabiados, aun@ue no cabien los eleentos a los @ue %acen re#erencia. /iense en la 8erar@uía de in6ocación de un sistea. Las #unciones de la arte suerior in6ocan a las #unciones situadas deba8o, @ue in6ocan a otras #unciones in#eriores 5 así sucesi6aente. "agine @ue una de las #unciones de ni6el in#erior se odi#ica de #ora @ue debe generar una e>ceción. i la e>ceción se corueba, la #ira de la #unción tendr= @ue a3adir una cl=usula t%ro?s. /ero esto signi#ica @ue todas las #unciones @ue in6o@uen nuestra #unción odi#icada tabién tendr=n @ue cabiarse ara caturar la nue6a
e>ceción o ara a3adir la corresondiente cl=usula t%ro?s en su #ira. E así inde#inidaente. *l resultado #inal es una cascada de cabios @ue asan desde los ni6eles in#eriores del software %asta los sueriores. La encasulación se roe 5a @ue todas las #unciones en la ruta de t%ro? deben conocer detalles de la e>ceción de ni6el in#erior. Coo el coetido de las e>ceciones es eritios rocesar errores a distancia, es una l=stia @ue las e>ceciones corobadas roan la encasulación de esta #ora. Las e>ceciones corobadas ueden ser ;tiles si tiene @ue crear una biblioteca crítica: tendr= @ue caturarlas. /ero en el desarrollo de alicaciones generales, los costes de deendencia sueran las 6enta8as.
Ofrecer conteEto )unto a las eEcepciones Las e>ceciones @ue genere deben roorcionar el conte>to adecuado ara deterinar el origen 5 la ubicación de un error. *n Ja6a, uede obtener un rastreo de ila de cual@uier e>ceción sin ebargo, no le indicar= el coetido de la #unción #allida. Redacte ensa8es de error in#orati6os 5 =selos 8unto a sus e>ceciones. Mencione la oeración #allida 5 el tio de #allo. i guarda registros en su alicación, inclu5a in#oración su#iciente ara oder registrar el error en la cl=usula catc%.
2efinir clases de eEcepción de acuerdo a las necesidades del in+ocador *>isten 6arias #oras de clasi#icar los errores. /odeos %acerlo or origen Hro6ienen de uno u otro coonenteI4 o or tio Hson #allos del disositi6o, de la red o errores de rograaciónI4. in ebargo, al de#inir clases de e>ceción en una alicación, debeos reocuaos rincialente en c2mo se capt%ran. eaos un obre e8elo de clasi#icación de e>ceciones. *s una instrucción tr51 catc%1#inall5 de la in6ocación de una biblioteca de terceros. (barca todas las e>ceciones @ue las in6ocaciones ueden generar: (CM*/ort ort X ne? (CM*/ort24 tr5 _`Ob ort.oen4 _`Od catc% -e6iceResonse*>cetion e4 _`Ob reort/ort*rrore4 logger.log_`Ob-e6ice resonse e>cetion, e4 _`Od catc% (TM22nloc&ed*>cetion e4 _`Ob reort/ort*rrore4 logger.lognloc& e>cetion, e4 _`Od catc% GM+*rror e4 _`Ob reort/ort*rrore4 logger.log-e6ice resonse e>cetion4 _`Od #inall5 _`Ob Y _`Od *sta instrucción contiene eleentos dulicados, algo @ue no debería sorrendeos. *n uc%os casos de control de e>ceciones, el traba8o @ue reali!aos es relati6aente est=ndar indeendienteente de la causa real. -ebeos registrar un error 5 aseguraos de
oder continuar. *n este caso, coo sabeos @ue el traba8o es el iso indeendienteente de la e>ceción, odeos sili#icar el código si incluios la (/" in6ocada 5 nos aseguraos de @ue de6uel6e un tio de e>ceción co;n: Local/ort ort X ne? Local/ort24 tr5 _`Ob ort.oen4 _`Od catc% /ort-e6iceailure e4 _`Ob reort*rrore4 logger.loge.getMessage4, e4 _`Od #inall5 _`Ob Y _`Od Buestra clase Local/ort es un sile en6oltorio @ue catura 5 traduce e>ceciones generadas or la clase (CM*/ort: ublic class Local/ort _`Ob ri6ate (CM*/ort inner/ort ublic Local/ortint ortBuber4 _`Ob inner/ort X ne? (CM*/ortortBuber4 _`Od ublic 6oid oen4 _`Ob tr5 _`Ob inner/ort.oen4 _`Od catc% -e6iceResonse*>cetion e4 _`Ob t%ro? ne? /ort-e6iceailuree4 _`Od catc% (TM22nloc&ed*>cetion e4 _`Ob t%ro? ne? /ort-e6iceailuree4 _`Od catc% GM+*rror e4 _`Ob t%ro? ne? /ort-e6iceailuree4 _`Od _`Od Y _`Od Los en6oltorios coo el de#inido ara (CM*/ort ueden ser u5 ;tiles. -e %ec%o, es recoendable en6ol6er (/" de terceros. (l %acerlo, se inii!an las deendencias: uede cabiar a otra biblioteca di#erente sin aenas robleas 5 el en6oltorio tabién #acilita iitar in6ocaciones de terceros cuando se rueba el código. na ;ltia 6enta8a es @ue no estaos liitados a las decisiones de dise3o de (/" de un deterinado #abricante. /uede de#inir una (/" @ue le resulte cóoda. *n el e8elo anterior, de#inios un ;nico tio de e>ceción ara el #allo de uertos 5 odeos escribir un código uc%o =s liio. ( enudo, una ;nica clase de e>ceción es su#iciente ara una !ona concreta del código. La in#oración en6iada con la e>ceción uede distinguir los errores. se clases di#erentes sólo ara caturar una e>ceción 5 eritir el aso de otra distinta.
2efinir el flu)o normal
i sigue los conse8os de aartados anteriores, reali!ar= una iortante searación entre la lógica eresarial 5 el control de errores. La a5oría de su código arecer= un algorito liio 5 sin adornos. in ebargo, el roceso desla!a la detección de errores %ada los bordes del rograa. -ebe en6ol6er (/" e>ternas ara oder generar sus roias e>ceciones 5 de#inir un controlador or encia del código ara oder rocesar c=lculos cancelados. *n uc%os casos es el en#o@ue =s acertado, ero en ocasiones con6iene no cancelar. eaos un e8elo, un código e>tra3o @ue sua gastos en una alicación de #acturación: tr5 _`Ob Meal*>enses e>enses X e>enseReort-(<.getMealselo5ee.get"-44 total ZX e>enses.getTotal4 _`Od catc%Meal*>ensesBotound e4 _`Ob total ZX getMeal/er-ie4 _`Od *n esta eresa, si las coidas son gastos, asan a #orar arte del total. i no lo son, los traba8adores reciben una cantidad diaria ara la coida. La e>ceción entorece la lógica. ería =s adecuado no tener @ue rocesar el caso esecial 5 el código sería uc%o =s sencillo: Meal*>enses e>enses X e>enseReort-(<.getMealselo5ee.get"-44 total ZX e>enses.getTotal4 H-e 6erdad @ue el código uede ser tan sileI /ues sí. /odeos cabiar *>enseReort-(< ara @ue siere de6uel6a un ob8eto Meal*>ense. i no %a5 gastos de coida, de6uel6e un ob8eto Meal*>ense @ue de6uel6e la dieta diaria coo total: ublic class /er-ieMeal*>enses ileents Meal*>enses _`Ob ublic int getTotal4 _`Ob QQ de6ol6er la dieta diaria redeterinada _`Od _`Od *s lo @ue se denoina Patr2n de Caso )special o?lerU. o?lerU. e crea una clase o se con#igura un ob8eto @ue rocese un caso esecial. (l %acerlo, el código cliente no tiene @ue rocesar coortaientos e>cecionales. -ic%os coortaientos se encasulan en un ob8eto de caso esecial.
Bo de+ol+er Bull Creo @ue toda descrición del control de errores debe encionar los eleentos rocli6es a errores. *l riero es de6ol6er null. e erdido la cuenta de la cantidad de alicaciones en @ue las @ue línea sí 5 línea tabién se corueba null: ublic 6oid register"te"te ite4 _`Ob i# ite X null4 _`Ob "teRegistr5 registr5 X eristenttore.get"teRegistr54 i# registr5 X null4 _`Ob "te e>isting X registr5.get"teite.get"-44 i# e>isting.get)illing/eriod4.%asRetailisting.registerite4 _`Od _`Od _`Od _`Od i traba8a en una base de código coo ésta, uede @ue no le are!ca tan ala, ero lo es. (l de6ol6er null, b=sicaente nos creaos traba8o 5 generaos robleas ara los in6ocadores. )asta con @ue #alte una corobación de null ara @ue la alicación ierda el control. He %a #i8ado en @ue no %a5 una corobación de null en la segunda línea de la instrucción i# anidadaI HKué sucedería en tieo de e8ecución si ersistenttore #uera nullI e generaría Bull/ointer*>cetion en tieo de e8ecución 5 se caturaría Bull/ointer*>cetion en el ni6el suerior o no. *n abos casos caso s es incorrecto. HKué debería %ace coo resuesta a la generación de Bull/ointer*>cetion desde el interior de su alicaciónI e uede a#irar @ue el roblea de este código es la ausencia de una corobación de null ero en realidad el roblea es su e>ceso. i siente la tentación de de6ol6er null desde un étodo, ruebe a generar una e>ceción o a de6ol6er un ob8eto de caso esecial. i in6oca un étodo @ue de6uel6a null desde una (/" de terceros, en6uél6alo en un étodo @ue genere una e>ceción o de6uel6a un ob8eto de caso esecial. *n uc%os casos, los ob8etos de caso esecial son un reedio sencillo. "agine @ue tiene el siguiente código: List]*lo5ee^ elo5ees X get*lo5ees4 i# elo5ees X null4 _`Ob #or*lo5ee e : elo5ees4 _`Ob total /a5 ZX e.get/a54 _`Od _`Od (%ora, get*lo5ees uede de6ol6er null, Hero es necesarioI i cabiaos get*lo5ee ara @ue de6uel6a una lista 6acía, odreos liiar el código: List]*lo5ee^ elo5ees X get*lo5ees4 #or*lo5ee e : elo5ees4 _`Ob total/a5 ZX e.get/a54 _`Od (#ortunadaente, Ja6a disone de Collections.et5List4 5 de6uel6e una lista
inutable rede#inida @ue odeos usar ara este coetido: ublic List]*lo5ee^ get*lo5ees4 _`Ob i# Y t%ere are no elo5ees Y4 return Collections.et5List4 _`Od i usa este tio de código, inii!ar= la resencia de Bull/ointer*>cetion 5 su código ser= =s liio.
Bo pasar Bull -e6ol6er null desde étodos es incorrecto, ero es eor asar null a étodos. ( enos @ue traba8e con una (/" @ue esere @ue ase null, debe e6itarlo siere @ue sea osible. eaos otro e8elo, un sencillo étodo @ue calcula una étrica ara dos untos: ublic class MetricsCalculator _`Ob ublic double >/ro8ection/oint , /oint 24 _`Ob return 2.> .>4 . _`Od Y _`Od HKué sucede cuando alguien asa null coo arguentoI calculator.>/ro8ectionnull, ne? /oint 2, W44 e genera Bull/ointer*>cetion, e6identeente. HCóo solucionarloI /odríaos crear un nue6o tio de e>ceción 5 generarla: ublic class MetricsCalculator _`Ob ublic double >/ro8ection/oint , /oint 24 _`Ob i# XXnull 2XXnull4 _`Ob t%ro? "n6alid(rguent*>cetion "n6alid arguent #or MetricsCalculator.>/ro8ection4 _`Od return 2.> .>4 . _`Od _`Od _`Od HMe8orI /uede @ue sea e8or @ue una e>ceción de untero nulo, ero recuerde @ue debe de#inir un controlador ara "n6alid(rguent*>cetion. HKué debe %acer el controladorI Ha5 alguna #ora correcta de %acerloI *>iste otra alternati6a, usar un gruo de a#iraciones: ublic class MetricsCalculator ublic double >/ro8ection_`Ob/oint , /oint 24 _`Ob assert X null : s%ould not be null assert 2 X null : 2 s%ould not be null return 2.> 1 l.>4 . _`Od _`Od *s docuentación correcta ero no soluciona el roblea. i alguien asa null,
seguir= roduciéndose un error de tieo de e8ecución. *n la a5oría de lengua8es de rograación no %a5 una #ora correcta de rocesar un null asado or accidente. Coo éste es el caso, el en#o@ue racional es iedir @ue se ase null de #ora redeterinada. i lo %ace, uede dise3ar código sabiendo @ue null nu ll en una lista de arguentos indica un roblea 5 los errores ser=n enores.
Conclusión *l código liio es legible ero tabién debe ser robusto. Bo son ob8eti6os ouestos. /odeos crear código liio 5 robusto si consideraos el control de errores una reocuación di#erente, algo @ue 6eos de #ora indeendiente desde nuestra nues tra lógica rincial. i soos caaces de lograrlo, ra!onareos ra !onareos de #ora indeendiente 5 odeos od eos auentar la caacidad de anteniiento de nuestro código.
(ibliograf:a ;Martin>: Agile Software Development: Principles, Patterns, and Practices, Robert C. Martin, /rentice all, 2002.
N !:mites or Jaes Grenning
Bo es %abitual @ue controleos todo el software de nuestros sisteas. *n ocasiones, ad@uirios a@uetes de terceros o usaos código abierto. *n otros casos, deendeos de e@uios de nuestra roia eresa ara roducir coonentes o subsisteas @ue utili!aos. -e alg;n odo debeos integrar este código e>terno con el nuestro. *n este caítulo 6ereos r=cticas 5 técnicas ara de#inir con claridad los líites de nuestro software.
8tilizar código de terceros *>iste una tensión natural entre el ro6eedor de una inter#a! 5 el usuario de la isa. Los ro6eedores de a@uetes 5 estructuras de terceros abogan or una caacidad de alicación global ara oder traba8ar en di6ersos entornos 5 atraer a un ;blico =s alio. Los usuarios, or su arte, desean una inter#a! centrada en sus necesidades concretas. *sta tensión uede ro6ocar robleas en los líites de nuestros sisteas. (naliceos 8a6a.util.Ma coo e8elo. Coo uede areciar en la siguiente lista. Ma tiene una alia inter#a! con nuerosas restaciones. *sta otencia 5 #le>ibilidad es u5 ;til, ero tabién uede ser un roblea. /or e8elo, nuestra alicación uede
generar un Ma 5 coartirlo. Buestra intención uede @ue sea @ue ninguno de los recetores del aa borre sus eleentos. /ero en la arte suerior de la lista encontraos el étodo clear4. Cual@uier usuario del aa uede borrarlo. < uede @ue nuestra con6ención de dise3o deterine @ue sólo se uedan alacenar ob8etos concretos en el aa, ero Ma no liita de #ora #iable los tios de ob8etos @ue adite. Cual@uier usuario uede a3adir eleentos de cual@uier tio a cual@uier aa. clear4 6oid 1 Ma contains$e5 tends
irobables, ero recuerde @ue se %an roducido al a3adir coatibilidad con genéricos en Ja6a . in duda %eos 6isto sisteas @ue iiden el uso de genéricos debido a la gran cantidad de cabios necesarios ara coensar el uso liberal de Ma. na #ora =s liia de usar Ma sería la siguiente. ( ning;n usuario ensor le iorta si se usan genéricos o no. *sa oción se %a con6ertido 5 siere debería serlo4 en un detalle de ileentación. ublic class ensors _`Ob ri6ate Ma sensors X ne? as%Ma4 ublic ensor get)5"dtring id4 _`Ob return ensor4 sensors.getid4 _`Od QQcorte _`Od La inter#a! en el líite Ma4 est= oculta. a conseguido e6olucionar sin aenas iacto en el resto de la alicación. *l uso de genéricos 5a no es un roblea 5a @ue la con6ersión 5 la adinistración de tios se rocesa dentro de la clase ensors. *sta inter#a! tabién se %a a8ustado 5 liitado a las necesidades de la alicación. Genera código =s #=cil de entender 5 con enor robabilidad de errores. La clase ensors uede alicar las reglas eresariales 5 de dise3o. Bo sugerios @ue se encasulen de esta #ora todos los usos de Ma, sino @ue no se ase Ma ni otras inter#aces en el líite4 or el sistea. i usa una inter#a! de líite coo Ma, anténgala dentro de la clase o la #ailia de clases en la @ue se use. *6ite de6ol6erla o acetarla coo arguento de (/" ;blicas.
#Eplorar - aprender l:mites *l código de terceros nos erite obtener a5or #uncionalidad en enos tieo. H/or dónde ee!aos cuando @uereos utili!ar un a@uete de tercerosI Buestra labor no es robar el código, ero sí crear ruebas ara el código de terceros @ue utiliceos. "agine @ue no es e6idente cóo usar una biblioteca de terceros. /odríaos erder uno o 6arios días en leer la docuentación 5 decidir cóo usarla. Tras ello, odríaos escribir el código ara usar el código de terceros 5 corobar si se coorta de la #ora eserada. Bo deberíaos sorrendeos or tener @ue reali!ar e>tensas sesiones de deuración intentando locali!ar errores en nuestro código o en el su5o. (render el código de terceros es colicado, 5 tabién integrarlo. acer abas cosas al iso tieo es el doble de colicado. Becesitaos un en#o@ue di#erente. *n lugar de e>erientar 5 robar el nue6o aterial en nuestro código de roducción, odríaos crear ruebas @ue @u e analicen nuestro entendiiento del código de terceros. Ji J i WVU Be?&ir& las denoina pr%ebas de aprendi(a0e . *n las ruebas de arendi!a8e, in6ocaos la (/" de terceros coo suuestaente la usaríaos en nuestra alicación. )=sicaente reali!aos e>erientos controlados ara corobar si la entendeos. Las ruebas se centran en lo @ue @uereos obtener de la (/".
Aprender log) "agine @ue desea usar el a@uete de (ac%e logV8 en lugar de su roio disositi6o
de registro ersonali!ado. Lo descarga 5 abre la =gina inicial de la docuentación. in una lectura e>%austi6a, crea el rier caso de rueba con la eseran!a de @ue escriba %ello en la consola. [Test ublic 6oid testLogCreate4 _`Ob Logger logger X Logger.getLoggerM5Logger4 logger.in#o%ello4 _`Od (l e8ecutarlo, el registrador genera un error @ue nos indica @ue necesitaos algo denoinado (ender. Tras in6estigar, descubrios @ue e>iste un eleento Console(ender. Creaos Console(ender 5 corobaos si %eos conseguido re6elar los secretos del registro en la consola. [Test ublic 6oid testLog(dd(ender4 _`Ob Logger logger X Logger.getLogger M5Logger4 Console(ender aender X ne? Console(ender4 logger.add(enderaender4 logger.in#o%ello4 _`Od *n esta ocasión descubrios @ue (ender carece de #lu8o de salida, algo e>tra3o, 5a @ue arece lógico @ue lo tu6iera. Tras recurrir a Google, robaos lo siguiente: [Test ublic 6oid testLog(dd(ender4 _`Ob Logger logger X Logger.getLoggerM5Logger4 logger.reo6e(ll(enders4 logger.add(enderne? Console(ender ne? /atternLa5out t n4, Console(ender.ET*M<T44 logger.in#o%ello4 _`Od unciona en la consola aarece un ensa8e con la alabra %ello. Resulta e>tra3o tener @ue indicarle a Console(ender @ue escriba en la consola. (l eliinar el arguento Console(ender.5stetra3o. i nos #i8aos en la docuentación, 6eos @ue el constructor Console(ender redeterinado no est= con#igurado, lo @ue no arece deasiado ob6io ni ;til. /arece =s bien un error o una inco%erencia inco%eren cia de logV8. Tras nue6as b;s@uedas en Google, in6estigaciones 5 ruebas, conseguios el Listado A1. eos descubierto cóo #unciona logV8 5 %eos codi#icado esos conociientos en un gruo de sencillas ruebas de unidad. !istado NF
LogTest.8a6a. ublic class LogTest ri6ate Logger logger [)e#ore
ublic 6oid initiali!e4 _`Ob logger X Logger.getLoggerlogger4 Logger.getLoggerlogger4 logger.reo6e(ll(enders4 Logger.getRootLogger4.reo6e(ll(enders4 _`Od [Test ublic 6oid basicLogger4 _`Ob )asicCon#igurator.con#igure4 logger.in#obasicLogger4 _`Od [Test ublic 6oid add(ender7it%trea4 _`Ob logger.add(enderne? Console(ender ne? /atternLa5out t n4, Console(ender.ET*M<T44 logger.in#oadd(ender7it%trea4 _`Od [Test ublic 6oid add(ender7it%outtrea4 _`Ob logger.add(enderne? Console(ender ne? /atternLa5out t n444 logger.in#oadd(ender7it%outtrea4 _`Od _`Od (%ora sabeos cóo iniciali!ar un sencillo registrador de consola 5 encasular ese conociiento en nuestra roia clase de registro ara @ue el resto de la alicación se aísle de la inter#a! de líite logV8.
!as pruebas de aprendiza)e son algo más 9ue gratuitas Las ruebas de arendi!a8e no cuestan nada. -e todas #oras, %eos tenido @ue arender la (/" 5 crear las ruebas #ue una #ora sencilla 5 aislada de ad@uirir esos conociientos. Las ruebas de arendi!a8e #ueron e>erientos recisos @ue eritieron auentar nuestros conociientos. Las ruebas no sólo son gratuitas, sino tabién rentables. Cuando aare!can nue6as 6ersiones del a@uete de terceros, e8ecutaos las ruebas de arendi!a8e ara corobar si %a5 di#erencias de coortaiento. Las ruebas de arendi!a8e deuestran @ue los a@uetes de terceros @ue usaos #uncionan de la #ora eserada. na 6e! integrados, no %a5 garantía de @ue el código de terceros sea coatible con nuestras necesidades. Los autores originales se 6er=n resionados ara cabiar el código cód igo 5 a8ustarlo a sus roias necesidades. Corregir=n Co rregir=n errores 5 a3adir=n nue6as #unciones. *n cada 6ersión surgir=n nue6os riesgos. i el a@uete de terceros cabia de una #ora incoatible con nuestras ruebas, lo sabreos al instante. "ndeendienteente de @ue necesite los conociientos roorcionados or las ruebas de arendi!a8e, un líite claro debe estar resaldado or un con8unto de ruebas r uebas
@ue e8erciten la inter#a! de la isa #ora @ue %ace el código de roducción. in estas ruebas de líites ara #acilitar la transición, odríaos conser6ar cons er6ar la 6ersión antigua =s tieo del necesario.
8sar código 9ue toda+:a no eEiste *>iste otro tio de líite, @ue seara lo conocido de lo desconocido. *n ocasiones, nuestro conociiento del código arece des6anecerse. Lo @ue %a5 al otro lado del líite es desconocido al enos or el oento4. *n ocasiones, decidios no irar =s all= del líite. ace a3os #oré arte de un e@uio de desarrollo de software ara un sistea de counicación or radio. abía un subsistea, el Transisor, @ue aenas conocíaos 5 cu5a inter#a! toda6ía no se %abía dise3ado. Coo no @ueríaos @uedaos arados, coen!aos a traba8ar ale8=ndonos de la arte desconocida del código. abíaos er#ectaente dónde acababa nuestro undo 5 coen!aba el nue6o. Mientras a6an!=baos, en ocasiones nos to=baos con este líite. (un@ue la ignorancia ocultaba nuestra 6isión =s all= del líite, sabíaos cóo @ueríaos @ue #uera la inter#a!. Kueríaos decirle al transisor algo coo lo siguiente: A0%star el transmisor en la frec%encia frec%encia proporcionada . emitir %na representaci2n anal2gica de los datos *%e provienen de este fl%0o"
Bo sabíaos cóo %acerlo 5a @ue toda6ía no se %abía dise3ado la (/". /or ello decidios deterinar desués los detalles. /ara no @uedaos blo@ueados, de#inios nuestra roia inter#a!. Le dios un nobre sencillo, Transitter. Le asignaos el étodo transit @ue acetaba una #recuencia 5 un #lu8o de datos. *s la inter#a! @ue dese=baos %aber tenido. Lo e8or de escribir la inter#a! @ue dese=baos %aber tenido era @ue la control=baos. *sto %ace @ue el código cliente sea =s legible 5 se ci3a a los ob8eti6os re6istos. *n la #igura A. se arecia @ue aislaos las clases CounicationsController de la (/" del transisor @ue no control=baos 5 estaba or de#inir4. (l usar nuestra roia inter#a! esecí#ica de la alicación, el código de CounicationsController era liio 5 e>resi6o. na 6e! de#inida la (/" del transisor, creaos Transitter(dater ara reducir las distancias. *l adatador WU encasulaba la interacción con la (/" 5 o#recía un ;nico unto en el @ue e6olucionaba.
igura A.. /redicción del transisor
*ste dise3o tabién nos o#rece un selloWNU en el código ara reali!ar ruebas. Con un eleento a&eTransitter, odeos robar las clases CounicationsController. Tabién odeos crear ruebas de líite una 6e! dise3ada la (/" Transitter ara aseguraos de @ue la utili!aos correctaente.
!:mites limpios *n los líites suceden cosas interesantes. Los cabios es una de ellas. Los dise3os de código correctos acoodan los cabios sin necesidad de grandes odi#icaciones. Cuando usaos código @ue no controlaos, %a5 @ue restar esecial atención a roteger nuestra in6ersión 5 aseguraos de @ue los cabios #uturos no son deasiado costosos. *l código en los líites re@uiere una searación e6idente 5 ruebas @ue de#inan e>ectati6as. -ebeos e6itar @ue el código cono!ca los detalles de terceros. *s =s aconse8able deender de algo @ue controleos @ue de algo @ue no controleos, 5 enos toda6ía si nos controla. Los líites de terceros se gestionan gracias a la resencia de untos ínios en el código @ue %agan re#erencia a los isos. /odeos en6ol6erlos coo %icios con Ma o usar un adatador ara con6ertir nuestra inter#a! er#ecta en la inter#a! roorcionada. *n cual@uier caso, el código se lee e8or, roue6e el uso co%erente e interno en el líite 5 %a5 enos untos de anteniiento cuando cabie el código de terceros.
(ibliograf:a ;(ec6322>: $est Driven Development , $ent )ec&, (ddison17esle5, 200W. Software, Gaa ;O$>: Design Patterns: )lements of e%sable b0ect riented Software et al., (ddison 7esle5, 9. ;5#!C>: orking )ffectivel. with 'egac. Code, (ddison17esle5, 200V.
@ Pruebas de unidad
Buestra ro#esión %a e6olucionado uc%o en los ;ltios 0 a3os. *n 99O nadie %abía oído %ablar del -esarrollo guiado or ruebas -G/4. /ara la a5oría, las ruebas de unidad eran e@ue3os #ragentos de código desec%able @ue cre=baos ara aseguraos de @ue nuestros rograas #uncionaban. *scribíaos clases 5 étodos, 5 desués código ad hoc ara robarlos, lo @ue ilicaba alg;n tio de rograa controlador @ue nos eritiera interactuar anualente con el rograa @ue %abíaos escrito. Recuerdo crear un rograa de CZZ ara un sistea incrustado de tieo real a ediados de la década de 990. *l rograa era un sencillo teori!ador con la siguiente #ira: 6oid Tier::c%eduleCoandCoand t%eCoand, int illiseconds4 La idea era sencilla el étodo e>ecute de Coand se e8ecutaba en un nue6o subroceso tras el n;ero eseci#icado de ilisegundos. *l roblea era cóo robarlo. Con#eccioné un sencillo rograa controlador @ue escuc%aba al teclado. Cada 6e! @ue se introducía un car=cter, se rograaba un coando @ue escribía el iso car=cter cinco segundos desués. "ntrodu8e una rítica elodía en el teclado 5 eseré a @ue se rerodu8era en antalla cinco segundos desués: E3 want-a-girl 0%st like-the-girl-who-marr ied dear old dad"F
"ncluso tarareé la elodía ientras ulsaba la tecla, 5 la 6ol6í a cantar cuando aarecieron los untos en la antalla. \sa #ue i rueba. Cuando 6i @ue #uncionaba 5 se lo ostré a is coa3eros, e des%ice del código de rueba. Coo %e a#irado, nuestra ro#esión %a e6olucionado uc%o. (%ora crearía una rueba @ue garanti!ara el #uncionaiento #unciona iento de %asta el =s ínio detalle del código. (islaría el código del sistea oerati6o en lugar de in6ocar las #unciones est=ndar de teori!ación. Las iitaría ara tener control total sobre el tieo. /rograaría coandos @ue de#inieran indicadores )ooleanos 5 a6an!aría el tieo, ara obser6ar los indicadores 5 asegurare de @ue asaran de #alse a true al cabiar el tieo al 6alor correcto. Cuando suerara una serie de ruebas, corobaría @ue #ueran adecuadas ara todo el @ue tu6iera @ue traba8ar con el código. Me aseguraría de corobar las ruebas 5 el código en el iso a@uete. í, %eos a6an!ado uc%o, ero nos @ueda uc%o or a6an!ar. Los o6iientos (gile 5 T-- %an aniado a uc%os rograadores a crear ruebas de unidad autoati!adas 5 cada 6e! son =s. /ero en esta alocada carrera or a3adir ruebas a nuestra discilina, uc%os rograadores %an asado or alto dos de los asectos =s sutiles e iortantes de dise3ar ruebas de calidad.
!as tres le-es del 2P Todos sabeos @ue el -G/ nos ide @ue riero creeos las ruebas de unidad, antes @ue el código de roducción. /ero esa nora es sólo la unta del iceberg. Tenga en cuenta las tres siguientes le5esWOU: Primera le-: Bo debe crear código de roducción %asta @ue %a5a creado una rueba de unidad @ue #alle. Segunda le-: Bo debe crear =s de una rueba de unidad @ue baste coo #allida 5 no coilar se considera un #allo. 3ercera le-: Bo debe crear =s código de roducción @ue el necesario ara suerar la rueba de #allo actual. *stas tres le5es generan un ciclo de unos W0 segundos de duración. Las ruebas 5 el código de roducción se crean de #ora con8unta, las ruebas unos segundos antes @ue el código. i traba8aos de esta #ora, creareos decenas de ruebas al día, cientos al es 5 iles al a3o. i traba8aos de esta #ora, las ruebas abarcar=n todos los asectos de nuestro código de roducción. *l taa3o de dic%as ruebas, @ue uede ser siilar al del código de roducción, uede suoner un roblea de adinistración.
4ealizar pruebas limpias ace unos a3os e idieron @ue dirigiera un e@uio @ue %abía decidido e>lícitaente @ue su código de rueba no debía antenerse con los isos est=ndares de calidad @ue su código de roducción. /odían inculir las reglas en sus ruebas de unidad. La reisa era FR=ido 5 directo. Bo era necesario @ue las 6ariables tu6ieran nobres adecuados, ni @ue las #unciones de rueba #ueran bre6es 5 descriti6as. Bo era necesario @ue el código de rueba estu6iera bien dise3ado. )astaba con @ue #uncionara 5 abarcara el código de roducción. /uede @ue algunos lectores ealicen con esta decisión. /uede @ue en el asado
creara el tio de ruebas @ue cree ara la clase Tier. uone un gran aso crear ese tio de ruebas desec%ables a dise3ar una s%ite de ruebas de unidad autoati!adas. /or ello, coo el e@uio @ue dirigía, uede decidir @ue ruebas incorrectas sea e8or @ue no tener ruebas. /ero el e@uio no se daba cuenta @ue tener ruebas incorrectas era igual o eor @ue no tener rueba alguna. *l roblea es @ue las ruebas deben cabiar de acuerdo a la e6olución del código. Cuanto enos liias sean, =s di#ícil es cabiarlas. Cuando =s enre6esado sea el código de rueba, =s robabilidades de @ue dedi@ue =s tieo a a3adir nue6as ruebas a la s%ite @ue el eleado en crear el nue6o código de roducción. (l odi#icar el código de roducción, las ruebas antiguas coien!an a #allar 5 el desastre iide @ue las ruebas se sueren, or lo @ue acaban or con6ertirse en un obst=culo interinable. *ntre 6ersiones, auentó el coste de antener la s%ite de ruebas de i e@uio. (cabó or con6ertirse en la rincial @ue8a entre los desarrolladores. Cuando los directores reguntaron sobre este auento, los desarrolladores des arrolladores cularon a las ruebas. ru ebas. (l #inal, se 6ieron obligados a descartar la s%ite de ruebas coleta. /ero sin una s%ite de ruebas erdieron la osibilidad de garanti!ar el #uncionaiento eserado de los cabios en el código. in una s%ite de ruebas no odían asegurar @ue los cabios en una arte del sistea no a#ectaran a otras di#erentes. Los de#ectos auentaron, lo @ue roició @ue teieran reali!ar cabios. -e8aron de liiar su código de roducción or iedo a @ue los cabios #ueran da3inos. *l código de roducción coen!ó a corroerse. corroers e. (l #inal, se @uedaron sin ruebas, con un código de roducción enara3ado 5 de#ectuoso, de#ec tuoso, clientes #rustrados 5 la sensación de @ue su es#uer!o les %abía #allado. *n cierto odo tenían ra!ón. u es#uer!o les %abía #allado. /ero #ue su decisión de eritir @ue las ruebas #ueran incorrectas incor rectas lo @ue ro6ocó el #allo. i %ubieran eleado ruebas liias, su es#uer!o no %abría % abría #allado. /uedo a#irarlo con cierta seguridad segur idad or@ue %e articiado 5 dirigido uc%os e@uios @ue %an tenido é>ito gradas a ruebas de unidad liias. La orale8a de la %istoria es sencilla: el código de rueba es tan iortante coo el de roducción. Bo es un ciudadano de segunda. Re@uiere concentración, dise3o 5 cuidado. -ebe ser tan liio coo el código de roducción.
!as pruebas propician posibilidades i sus ruebas no son liias, las erder=. E sin ellas ierde lo iso @ue %ace @ue su código de roducción sea #le>ible. í, %a leído bien. Las ruebas de unidad son las @ue %acen @ue el código sea #le>ible 5 se ueda antener 5 reutili!ar. La ra!ón es sencilla. i tiene ruebas, no tendr= iedo a reali!ar cabios en el código. in ruebas, cada cabio es un osible error. "ndeendienteente de la #le>ibilidad de su ar@uitectura, de la di6isión del dise3o, sin ruebas tendr= iedo a reali!ar cabios or la osibilidad de a3adir errores no detectados. /ero con las ruebas ese iedo desaarece. Cuanto a5or sea el alcance de sus ruebas, enos iedo tendr=. /odr= /odr = odi#icar el código con total iunidad, aun@ue su ar@uitectura no sea la e8or 5 el dise3o sea ediocre. /odr= e8orar la ar@uitectura 5 el dise3o sin iedo alguno.
/or tanto, disoner de una s%ite autoati!ada de ruebas de unidad @ue cubran el código de roducción es la cla6e ara antener liio el dise3o 5 la ar@uitectura. Las ruebas roorcionan las osibilidades, o sibilidades, 5a @ue eriten el cabio. i sus ruebas no son liias, la caacidad de odi#icar el código se 6er= Liitada 5 erder= la osibilidad de e8orar la estructura de dic%o código. Cuanto enos liias sean las ruebas, enos lo ser= el código. *n ;ltia instancia erder= las ruebas 5 el código se corroer=.
Pruebas limpias HKué %ace @ue una rueba sea liiaI Tres eleentos: legibilidad, legibilidad 5 legibilidad. La legibilidad es sin duda =s iortante en las ruebas de unidad @ue en el código de roducción. HKué %ace @ue una rueba sea legibleI Lo iso @ue en el código: claridad, silicidad 5 densidad de e>resión. *n una rueba debe decir uc%o con el enor n;ero de e>resiones osible. í8ese en el código de itBesse del Listado 91. *stas tres ruebas son di#íciles de entender 5 sin duda se ueden e8orar. /or un lado, %a5 uc%o código dulicado GU en las in6ocaciones reetidas a add/age 5 assertubtring. obre todo, este código se carga con detalles @ue inter#ieren con la e>resi6idad de la rueba. !istado @F
eriali!ed/ageResonderTest8a6a. ublic 6oid testGet/ageieratc%5(s+l4 t%ro?s *>cetion _`Ob cra?ler.add/ageroot, /at%/arser.arse/agetroot4, re@uest4 tring >l X resonse.getContent4 assert*@ualste>tQ>l, resonse.getContentT5e44 assertubtring]nae^/agel4 assertubtring]nae^/ageT?o]Qnae^, >l4 assertubtring]nae^C%ildl4 _`Od ublic 6oid testGet/ageieratc%5(s+l-oesntContain5bolicLin&s4 t%ro?s *>cetion _`Ob 7i&i/age age
7i&i/age/roerties roerties X data.get/roerties4 7i&i/age/roert5 s5Lin&s X roerties.set5bolic/age./R*RTEB(M*4 s5Lin&s.set5/age, /ageT?o4 agetroot4, re@uest4 tring >l X resonse.getContent4 assert*@ualste>tQ>l, resonse.getContentT5e44 assertubtring]nae^/agel4 assertubtring]nae^/ageT?o]Qnae^, >l4 assertubtring]nae^C%ildl4 assertBotubtring5/age, >l4 _`Od ublic 6oid testGet-ata(stl4 t%ro?s *>cetion _`Ob cra?ler.add/ageroot, /at%/arser.arseTest/agetroot4, re@uest4 tring >l X resonse.getContent4 assert*@ualste>tQ>l, resonse.getContentT5e44 assertubtringtest age, >l4 assertubtring]Test, >l4 _`Od í8ese en las in6ocaciones de /at%/arser. Trans#oran cadenas en instancias de /age/at% usadas or las ara3as. *sta trans#oración es totalente irrele6ante ara la rueba 5 ;nicaente colica su coetido. Los detalles circundantes circundan tes a la creación del resondedor 5 la obtención 5 con6ersión de la resuesta tabién sobran. Tabién la #ora de crear la RL de solicitud a artir de un recurso 5 un arguento contribuí a crear este código, or lo @ue tengo todo el derec%o a criticarlo4. (l #inal, el código no se %a dise3ado de #ora legible. *l lector se 6e rodeado de iles de detalles @ue debe corender antes de @ue las ruebas tengan sentido. í8ese a%ora en las ruebas e8oradas del Listado 912. acen e>actaente lo iso, ero se %an re#actori!ado de #ora =s clara 5 descriti6a. !istado @F eriali!ed/ageResonderTest.8a6a re#actori!ado4 ublic 6oid testGet/ageierarc%5(s+l4 t%ro?s *>cetion _`Ob a&e/ages/age
assertResonse"s+ML4 assertResonseContains ]nae^/agecetion _`Ob 7i&i/age age X a&e/age/agecetion _`Ob a&e/age7it%ContentTest/age
!engua)e de pruebas espec:fico del dominio Las ruebas del Listado 912 ilustran la creación de un lengua8e esecí#ico del doinio ara sus ruebas. *n lugar de usar las (/" @ue los rograadores elean ara aniular el sistea, creaos una serie de #unciones 5 utilidades @ue usan dic%as (/" 5 @ue #acilitan la escritura 5 la lectura de las ruebas. *stas #unciones 5 utilidades se con6ierten en una (/" eseciali!ada usada or las ruebas. on un lengua8e de ruebas @ue los rograadores usan ersonalente ara crear sus ruebas 5 ara a5udar a los @ue desués las lean. *sta (/" de ruebas no se dise3a con antelación, sino @ue e6oluciona con la re#actori!ación continuada del código de rueba. (l igual @ue re#actori!aos el Listado 91 en el Listado 912, los rograadores discilinados re#actori!an su código de rueba en 6ersiones =s sucintas 5 e>resi6as.
8n estándar dual *n un sentido, el e@uio @ue encionaos antes tenía ra!ón. *l código de la (/" de ruebas tiene un con8unto de est=ndares de ingeniería di#erentes al código de roducción. roducc ión. Tabién tiene @ue ser sencillo, sucinto 5 e>resi6o, ero no tan e#ica! coo el código de roducción. -esués de todo, se e8ecuta en un entorno de rueba, no de roducción, roducción, 5 cada entorno tiene sus roias necesidades. í8ese en la rueba del Listado 91W. La cree coo arte de un rototio de sistea de control edioabiental. in entrar en detalles, se arecia @ue esta rueba corueba @ue la alara de ba8a teeratura, el calentador 5 el #uelle estén acti6ados cuando la teeratura sea deasiado #ría. !istado @FG
*n6ironentControllerTest.8a6a [Test ublic 6oid turncetion _`Ob %?.setTe7(ET<<Ccetion _`Ob ?a5TooCold4 assert*@uals)c%L, %?.gettate44 _`Od *6identeente, %e ocultado el detalle de la #unción tic creando una #unción ?a5TooCold. /ero lo iortante es la e>tra3a cadena de assert*@uals. Las a5;sculas signi#ican acti6ado 5 las in;sculas desacti6ado, 5 las letras siere aarece en este orden: _`Ob%eater, blo?er, cooler, %i1te1alar, lo1te1alar_`Od.
(un@ue r=cticaente sea un inculiiento de las reglas de asignación entalW9U, en este caso arece aroiado. na 6e! @ue conoceos el signi#icado, la 6ista asa or la cadena 5 odeos interretar los resultados. La lectura de la rueba es casi un lacer. í8ese en el Listado 91 5 coruebe con @ué #acilidad entiende las ruebas. !istado @F *n6ironentControllerTest.8a6a una selección a5or4. [Test ublic 6oid turncetion _`Ob tooot4 assert*@uals%)C%l, %?.gettate44 _`Od [Test ublic 6oid turncetion _`Ob tooCold4 assert*@uals)c%l, %?.gettate44 _`Od [Test ublic 6oid turncetion _`Ob ?a5Tooot4 assert*@uals%)CL, %?.gettate44 _`Od [Test ublic 6oid turncetion _`Ob ?a5TooCold4 assert*@uals)c%L, %?.gettate44 _`Od La #unción gettate se reroduce en el Listado 91N. Bo es un código u5 e#ica!. /ara @ue lo sea, deberíaos %aber usado tring)u##er. !istado @FL
Moc&Controlard?are.8a6a. ublic tring gettate4 _`Ob tring state X state ZX %eater I : % state ZX blo?er I ) : b state ZX cooler I C : c state ZX %iTe(lar I : % state ZX loTe(lar I L : l return state _`Od tring)u##er es oco atracti6o. "ncluso en código de roducción, intento e6itarlo si el coste es ínio, coo odría suceder en el Listado 91N. /ero esta alicación es claraente un sistea incrustado en tieo real 5 es robable @ue los recursos del e@uio 5 la eoria estén liitados. in ebargo, el entorno de ruebas es irobable @ue lo esté. *s la naturale!a del est=ndar dual. a5 cosas @ue nunca %aría en un entorno de roducción totalente 6=lidas ara un entorno de rueba. uelen ser robleas de eoria o e#icacia
de la C/, ero nunca robleas de liie!a.
8na afirmación por prueba *>iste una escuela de ensaientoV0U @ue a#ira @ue todas las #unciones de rueba de una rueba Jnit sólo deben tener una instrucción de a#iración. /uede arecer una regla draconiana ero la 6enta8a se arecia en el Listado 91. Las ruebas llegan a una isa conclusión, @ue se entiende de #ora r=ida 5 sencilla. H/ero @ué sucede con el Listado 912I Bo arece ra!onable a#irar @ue el resultado es +ML 5 @ue contiene deterinadas subcadenas. in ebargo, odeos di6idir la rueba en dos, cada una con una a#iración concreta, coo se uestra en el Listado 9.O. !istado @F= eriali!ed/ageResonderTest8a6a una sola a#iración4. ublic 6oid testGet/ageierarc%5(s+l4 t%ro?s *>cetion _`Ob gi6en/ages/agecetion _`Ob gi6en/ages/agecesi6o ara un roblea tan enor. (l #inal, oto or las a#iraciones ;ltiles del Listado 912. Considero @ue la regla de una sola a#iración es una directri! adecuadaVWU. iere intento crear un lengua8e de ruebas esecí#ico del doinio @ue la coleente, coo en el Listado 91, ero no rec%a!o incluir =s de una a#iración en una rueba. Creo @ue lo e8or @ue odeos decir es @ue el n;ero de a#iraciones de una rueba debe ser ínio.
8n solo concepto por prueba /uede @ue una regla =s indicada sea robar un ;nico conceto en cada #unción de rueba. Bo @uereos e>tensas #unciones @ue rueben una cosa cos a di#erente tras otra, coo sucede en el Listado 91A. *sta rueba debería di6idirse en tres di#erentes @ue robaran tres
cosas distintas. (l cobinarlas en la isa #unción se obliga al lector a deterinar or @ué cada sección se ubica en ese unto 5 @ué rueba dic%a sección. !istado @FN Q arias ruebas ara el étodo addMont%s4. Q ublic 6oid test(ddMont%s4 _`Ob erial-ate d X erial-ate.create"nstanceW, , 200V4 erial-ate d2 X erial-ate.addMont%s, d4 assert*@ualsW0, d2.get-a5<#Mont%44 assert*@ualsN, d2.getMont%44 assert*@uals200V, d2.getEEEE44 erial-ate dW X erial-ate.addMont%s2, d4 assert*@ualsW, dW.get-a5<#Mont%44 assert*@ualsO, dW.getMont%44 assert*@uals200V, dW.getEEEE44 erial-ate dV X erial-ate.addMont%s, erial-ate.addMont%s, d44 assert*@ualsW0, dV.get-a5<#Mont%44 assert*@ualsO, dV.getMont%44 assert*@uals200V, dV.getEEEE44 _`Od Las tres #unciones deberían ser las siguientes: -ado el ;ltio día de un es con W días coo a5o4: Cuando se a3ade un es, si el ;ltio día de ese es es el W0 coo en 8unio4, entonces la #ec%a debe ser el día W0 de ese es, no el W. Cuando se a3aden dos eses a esa #ec%a, si el ;ltio es tiene W días, entonces la #ec%a debe ser el día W. -ado el ;ltio día de un es con W0 días coo 8unio4: Cuando se a3ade, si el ;ltio día de ese es tiene W días, entonces la #ec%a debe ser el W0, no el W. *>resado de esta #ora, se arecia @ue e>iste una regla general entre las distintas ruebas. (l increentar el es, la #ec%a no uede ser a5or @ue su ;ltio día. *sto ilica @ue al increentar el es en el 2A de #ebrero debe generarse el 2A de ar!o. alta esa rueba 5 con6endría @ue la escribiéraos. (sí ues, no son las ;ltiles a#iraciones del Listado 91A las causantes del roblea, sino el %ec%o de @ue se rueba ru eba =s de un conceto. /robableente la regla reg la ótia sea inii!ar el n;ero de acti6os or conceto 5 robar un solo conceto or #unción de rueba.
$.I.4.S.3.;> Las ruebas liias siguen otras cinco reglas, cu5as iniciales #oran las siglas "RT en inglés: Kast 4: 4: Las reglas deben ser r=idas 5 e8ecutarse de #ora r=ida. i lo 4apidez Kast %acen lentaente, no las e8ecutar= con #recuencia. (l no %acerlo, no detectar= los robleas con la su#iciente antelación coo ara solucionarlos. s olucionarlos. Bo se sentir= con libertad ara liiar el código, @ue acabar= corroiéndose. cor roiéndose.
4: Las ruebas no deben deender entre ellas. na Independencia 3ndependent 3ndependent 4: rueba no debe establecer condiciones ara la siguiente. -ebe oder e8ecutar cada rueba de #ora indeendiente 5 en el orden @ue desee. i las ruebas deenden unas de otras, la riera @ue #alle ro6ocar= una sucesión s ucesión de #allos, di#icultar= el diagnóstico 5 ocultar= e#ectos osteriores. epeatable4: Las ruebas deben ode reetirse en cual@uier entorno. 4epetición epeatable -ebe oder e8ecutarlas en el entorno de roducción, en el de calidad 5 en su ort=til de caino a casa en un tren sin red. i no uede reetir las ruebas en cual@uier entorno, siere tendr= una e>cusa de su #allo. Tabién 6er= @ue no uede e8ecutar las ruebas si el entorno no est= disonible. 4: Las ruebas deben tener un resultado Kalidación automática Self->alidating 4: booleano: o aciertan o #allan. Bo debe tener @ue leer un e>tenso arc%i6o de registro ara ar a saber si una rueba %a acertado, ni coarar anualente dos arc%i6os de te>to distintos ara ello. i las ruebas no se 6alidan auto=ticaente, el #allo uede ued e ser sub8eti6o 5 la e8ecución de las ruebas uede re@uerir una e>tensa e6aluación anual. Puntualidad $imel.4: Las ruebas deben crearse en el oento reciso: antes del código de roducción @ue %ace @ue acierten. i crea las ruebas desués del código de roducción, uede @ue resulte di#ícil robarlo. robar lo. /uede decidir @ué arte del código de roducción sea deasiado di#ícil de robar. robar . Bo dise3e código de roducción @ue no se ueda robar.
Conclusión (enas %eos abordado la suer#icie de este tea. -e %ec%o, se odría crear un libro entero sobre ruebas liias. Las ruebas son tan iortantes ara la salud de un ro5ecto coo el código de roducción. /uede /u ede @ue incluso =s, 5a @ue conser6an 5 e8oran la #le>ibilidad, caacidad de anteniiento 5 reutili!ación del código de roducción. /or ello, intente @ue sean liias. Traba8e ara ar a @ue resulten e>resi6as 5 concisas. "n6ente (/" de rueba @ue act;en coo lengua8e esecí#ico del doinio @ue le a5ude a crear las ruebas. i de8a @ue las ruebas se corroan, suceder= lo iso con el código de roducción. Mantenga liias las ruebas.
(ibliograf:a ;4Spec>: Spec: =ehavior Driven Development for %b. Programmers, (sla& ellesa5, -a6id C%elis&5, /ragatic )oo&s%el#, 200A. Software, Gaa ;O$>: Design Patterns: )lements of e%sable b0ect riented Software et al., (ddison17esle5, 99N.
< Clases con Je## Langr
asta a%ora nos %eos centrado en escribir bien líneas 5 blo@ues de código. Bos %eos adentrado en la correcta coosición de las #unciones 5 en su interrelación. /ero a esar de la atención dedicada a la e>resi6idad e>res i6idad de las instrucciones 5 las #unciones, no tendreos código liio %asta @ue nos #i8eos en los ni6eles sueriores de su organi!ación. ableos sobre clases.
Organización de clases -e acuerdo a la con6ención est=ndar de Ja6a, una clase debe coen!ar con una lista de 6ariables. Las constantes est=ticas ;blicas, si e>isten, deben aarecer riero. Tras ello, las 6ariables est=ticas ri6adas 5 desués las 6ariables de instancia ri6adas. Bo suele ser necesario usar 6ariables ;blicas. Las #unciones ;blicas deben seguir a la lista de 6ariables. "ncluios las utilidades ;blicas in6ocadas or una #unción #un ción ;blica tras la roia #unción ;blica. *ste sistea cule la regla descendente 5 erite @ue el rograa se lea coo un artículo de eriódico.
#ncapsulación Kuereos @ue nuestras 6ariables 5 #unciones de utilidad sean ri6adas, ero no es irescindible. *n ocasiones odeos roteger una 6ariable o #unción de utilidad ara @ue sea accesible ara una rueba. Las reglas andan. i una regla del iso a@uete tiene @ue in6ocar una #unción o acceder a una 6ariable, %aceos @ue tenga =bito rotected o de a@uete. in ebargo, riero 6ereos una u na #ora de antener la ri6acidad. La rela8ación de la encasulación siere es un ;ltio resorte.
!as clases deben ser de tama%o reducido La riera regla de las clases es @ue deben ser de taa3o reducido. La segunda regla es @ue deben ser toda6ía =s reducidas. Bo, no 6aos a reetir el iso te>to en el caítulo sobre las #unciones, ero coo sucede con las #unciones, el taa3o reducido es lo rincial a la %ora de dise3ar una clase. E la regunta inediata es @ué ni6el de reducción. Con las #unciones edidos el taa3o contando líneas #ísicas. Con las clases usaos otra edida distinta: las resonsabilidadesVU. *l Listado 01 uestra una clase, uer-as%board, @ue uestra O0 étodos ;blicos. Muc%os rograadores estar=n de acuerdo en @ue es un taa3o e>cesi6o. (lgunos denoinarían a uer-as%board una clase -ios. !istado tends Jrae ileents Meta-ataser ublic tring getCustoi!erLanguage/at%4 ublic 6oid set5steCon#ig/at%tring s5steCon#ig/at%4 ublic tring get5steCon#ig-ocuent4 ublic 6oid set5steCon#ig-ocuenttring s5steCon#ig-ocuent4 ublic boolean getGurutate4 ublic boolean getBo6icetate4 ublic boolean get<enourcetate4 ublic 6oid s%o?
ublic tring getCurrent-ir4 ublic 6oid setCurrent-irtring ne?-ir4 ublic 6oid udatetatusint dot/os, int ar&/os4 ublic ClassU get-ata)aseClasses4 ublic Metadataeeder getMetadataeeder4 ublic 6oid add/ro8ect/ro8ect ro8ect4 ublic boolean setCurrent/ro8ect/ro8ect ro8ect4 ublic boolean reo6e/ro8ect/ro8ect ro8ect4 ublic Meta/ro8ecteader get/rograMetadata4 ublic 6oid reset-as%board4 ublic /ro8ect load/ro8ecttring #ileBae, tring ro8ectBae4 ublic 6oid setCana6eMetadataboolean cana6e4 ublic Meta4 ublic 6oid roert5*ditedReaintMeta
ublic "deMenu)ar get"deMenu)ar4 ublic 6oid s%o?elerMeta
Hu#icienteente reducidoI ublic class uer-as%board e>tends Jrae ileents Meta-ataser ublic Coonent getLastocusedCoonent4 ublic 6oid setLastocusedCoonent lastocused4 ublic int getMa8orersionBuber4 ublic int getMinorersionBuber4 ublic int get)uildBuber4 _`Od Cinco étodos no es deasiado, H6erdadI *n este caso sí 5a @ue a esar del reducido n;ero de étodos, uer-as%board tabién tiene deasiadas resonsabilidades. *l nobre de una clase debe describir las resonsabilidades @ue desee3a. -e %ec%o, el nobre es la riera #ora ara deterinar el taa3o de una clase. i no odeos deri6ar un nobre conciso conc iso ara una clase, seguraente sea se a deasiado e>tenso. Cuanto =s abiguo sea el nobre de la clase, =s robabilidades %a5 de @ue tenga deasiadas resonsabilidades. /or e8elo, los nobres de clase con alabras coo /rocessor, Manager o uer suelen indicar una desa#ortunada acuulación de resonsabilidades. Tabién debeos ser caaces de escribir una bre6e descrición de la clase en unas 2 alabras, sin usar las alabras Fsi, Fo, 5 Fo ero. HCóo describiríaos uer-as%boardI: uer-as%board erite acceder al coonente con el en#o@ue 5 nos erite controlar los n;eros de 6ersión 5 roducto. roducto. *l rier 5 indica @ue uer-as%board tiene deasiadas resonsabilidades.
#l Principio de responsabilidad nica *l /rinciio de resonsabilidad ;nica Single esponsibilit. Principle, R/4VNU indica @ue una clase o ódulo debe tener uno 5 sólo un oti6o ara cabiar. *ste rinciio nos indica la de#inición de resonsabilidad 5 una directri! ara el taa3o de la clase. Las clases sólo deben tener una resonsabilidad, un oti6o ara cabiar. La clase uer-as%board aarenteente reducida del Listado 012 tiene dos oti6os ara cabiar. /riero, controla in#oración de 6ersión @ue suuestaente debe actuali!arse cada 6e! @ue se coercialice el software. /or otra arte, gestiona coonentes de Ja6a ?ing un deri6ado de Jrae, la reresentación ?ing de una 6entana de "G de ni6el suerior4. in duda, @uerreos cabiar el n;ero de 6ersión si cabiaos el código ?ing, ero lo contrario no es necesario: odríaos cabiar la in#oración de 6ersión en #unción de los cabios de otro código del sistea. La identi#icación de resonsabilidades los oti6os del cabio4 nos erite reconocer 5 e8orar las abstracciones en nuestro código. /odeos e>traer los tres étodos de uer-as%board relacionados con la in#oración de 6ersiones
en una clase indeendiente coo ersion 6éase el Listado 01W.4 La clase ersion es una construcción @ue se uede reutili!ar en otras alicaciones. !istado
Co/esión Las clases deben tener un n;ero reducido de 6ariables de instancia. Los étodos de una clase deben aniular una o 6arias de dic%as 6ariables. /or lo general, cuantas =s
6ariables aniule un étodo, =s co%esión tendr= con su clase. na clase en la @ue cada 6ariable se usa en cada étodo tiene una co%esión =>ia. /or lo general, no es recoendable ni osible crear este tio de clases ero @uereos @ue la co%esión de nuestras clases sea ele6ada. i lo lograos, signi#ica @ue los étodos 5 6ariables de la clase deenden unos de otros 5 act;an coo un todo lógico. í8ese en la ileentación de tac& en el Listado 01V. *s una clase u5 consistente. -e los tres étodos, sólo si!e4 no usa abas 6ariables. !istado iste al enos una clase @ue intenta %uir de la clase de a5or taa3o. -ebe intentar searar las 6ariables 5 étodos en dos o =s clases ara @ue las nue6as sean =s consistentes.
Mantener resultados consistentes en muc/as clases de tama%o reducido La di6isión de grandes #unciones en otras =s e@ue3as auenta la roli#eración de clases. "agine una gran #unción con nuerosas 6ariables declaradas. "agine @ue desea e>traer una e@ue3a arte de esa #unción en otra indeendiente. in ebargo, el código @ue e>trae usa cuatro de las 6ariables declaradas en la #unción. H-ebe asar las cuatro 6ariables coo arguentos a la nue6a #unciónI *n absoluto. i ascendeos estas cuatro 6ariables a 6ariables de instancia de la clase, odreos e>traer el código sin asar las 6ariables. Resultaría =s sencillo di6idir la #unción en e@ue3os #ragentos. -esa#ortunadaente, eso signi#icaría @ue nuestras clases erderían co%esión 5a @ue acuularían =s 5 =s 6ariables de instancia @ue sólo e>isten ara @ue otras #unciones las
coartan. /ero un oento. i aenas e>isten #unciones @ue coartan deterinadas 6ariables, Hno son entonces una clase con derec%o roioI /or suuesto. Cuando las clases ierdan co%esión, di6ídalas. /or tanto, di6idir una gran #unción en otras =s reducidas tabién nos erite di6idir 6arias clases =s reducidas. -e este odo e8ora la organi!ación del rograa 5 su estructura resulta =s transarente. Coo e8elo, usareos un e8elo obtenido del libro de $nut% 'iterate Programming VOU. *l Listado 01 uestra una traducción a Ja6a del rograa /rint/ries de $nut%. /ara %acerle 8usticia, no es el rograa @ue creó sino el resultado generado or su %erraienta 7*). Lo usaos a@uí or ser un agní#ico unto de artida ara di6idir una #unción de gran taa3o en 6arias #unciones 5 clases =s reducidas. !istado
/rint/ries.8a6a ac&age literate/ries ublic class /rint/ries _`Ob ublic static 6oid aintringU args4 _`Ob #inal int M X 000 #inal int RR X 0 #inal int CC X V #inal int 77 X 0 #inal int
B X 2 J/R"M* X true ?%ile B ] cesi6o 5 %a5 deasiadas 6ariables e>tra3as. Coo ínio, la #unción debería di6idirse en otras =s e@ue3as. Los listados del 0.N al 0.A uestran la di6isión del código del Listado 01 en clases 5 #unciones de enor taa3o, ade=s de los nobres elegidos ara dic%as clases, #unciones 5 6ariables. !istado
#inal int R<7/*R/(G* X 0 #inal int C
int #irst"nde><#LastRo?"nRo? X #irst"nde>"nRo? ]X #irst"nde><#LastRo?"nRo?ZZ4 _`Ob rintRo?#irst"nde>"nRo?, last"nde>"nRo?, int last"nde> X #irst"nde>"nRo? Z colun ro?s/er/age i# inde> ]X last"nde>U4 _`Od _`Od ri6ate 6oid rint/ageeadertring ageeader, int ageBuber4 _`Ob rinttrea.rintlnageeader Z 111 /age Z ageBuber4 rinttrea.rintln4 _`Od ublic 6oid set
int rie"nde> X #or int candidate X W rie"nde> ] ries.lengt% candidate ZX 24 _`Ob i# is/riecandidate44 riesrie"nde>ZZU X candidate _`Od _`Od ri6ate static boolean is/rieint candidate4 _`Ob i# isLeastRele6antMultile<#Be>tLarger/rieactorcandidate44 _`Ob ultiles<#/rieactors.addcandidate4 return #alse _`Od return isBotMultile<#(n5/re6ious/rieactorcandidate4 _`Od ri6ate static boolean isLeastRele6antMultile<#Be>tLarger/rieactorint candidate4 _`Ob int ne>tLarger/rieactor X riesultiles<#/rieactors.si!e4U int leastRele6antMultile X ne>tLarger/rieactor ne>tLarger/rieactor return candidate XX leastRele6antMultile _`Od ri6ate static boolean isBotMultile<#(n5/re6ious/rieactorint candidate4 _`Ob #or int n X n ] ultiles<#/rieactors.si!e4 nZZ4 _`Ob i# isMultile<#Bt%/rieactorcandidate, n44 return #alse _`Od return true _`Od ri6ate static boolean isMultile<#Bt%/rieactorint candidate, int n4 _`Ob return candidate XX sallesttensos 5 descriti6os. /or otra arte, usa declaraciones de #unciones 5 clases coo coentarios del código. /or ;ltio, usaos
esacios en blanco 5 técnicas de #orato ara antener la legibilidad. *l rograa se %a di6idido en tres resonsabilidades rinciales. La arte rincial se inclu5e en la clase /rie/rinter, resonsable de controlar el entorno de e8ecución. Cabia si se odi#ica el étodo de in6ocación. /or e8elo, si este rograa se con6ierte en un ser6icio <(, es la clase @ue se 6er= a#ectada. Ro?Colun/age/rinter sabe cóo alicar #orato a una lista de n;eros con una deterinada cantidad de #ilas 5 colunas. i es necesario cabiar el #orato del resultado, es la clase @ue se 6er= a#ectada. La clase /rieGenerator sabe cóo generar una lista de n;eros rios. Bo se crear= una instancia coo ob8eto. La clase es sólo un =bito ;til en el @ue declarar 5 ocultar sus 6ariables. *sta clase cabia si se odi#ica el algorito ara calcular n;eros rios. Bo %eos reescrito el rograa. Bo %eos ee!ado de cero 5 los %eos 6uelto 6u elto a dise3ar. *n realidad, si se #i8a atentaente en los dos rograas, 6er= @ue usan los isos algoritos 5 ecanisos. *l cabio se %a reali!ado creando una s%ite de ruebas @ue 6eri#ican el coortaiento reciso del rier rograa. Tras ello, se alican nuerosos cabios ínios, de uno en uno. Tras cada cabio, se e8ecuta el rograa ara garanti!ar @ue el coortaiento no 6aría. /aso a aso, el rier rograa se liia 5 se trans#ora en el segundo.
Organizar los cambios *n uc%os sisteas, el cabio es continuo. Cada cabio suone un riesgo de @ue el resto del sistea no #uncione de la #ora eserada. *n un sistea liio organi!aos las clases ara reducir los riesgos de los cabios. La clase @l del Listado 019 se usa ara generar cadenas KL de #ora correcta con los etadatos adecuados. *s un traba8o continuo 5, coo tal, no adite #unciones KL coo instrucciones udate. Cuando la clase @l tenga @ue aditir una instrucción udate, tendreos @ue abrirla ara reali!ar odi#icaciones. *l roblea de abrir una clase es el riesgo @ue conlle6a. Cual@uier odi#icación uede a#ectar a otro código de la clase. -ebe robarse concien!udaente. !istado
ri6ate tring lace%olderListColunU coluns4 _`Od La clase @l debe cabiar al a3adir un nue6o tio de instrucción. Tabién debe cabiar cuando 6arieos los detalles de un tio de instrucción concreto or e8elo, si teneos @ue odi#icar la #uncionalidad select ara aditir selecciones secundarias. *stos dos oti6os de cabio signi#ican @ue la clase @l incule R/. /odeos detectar este inculiiento desde un unto de 6ista organi!ati6o. *l étodo outline de @l uestra @ue %a5 étodos ri6ados, coo select7it%Criteria, @ue arecen relacionarse ;nicaente con instrucciones select. *l coortaiento de étodos ri6ados alicados a un e@ue3o subcon8unto de una clase uede ser una %eurística ;til ara detectar !onas @ue e8orar. in ebargo, la 6erdadera ra!ón debe ser el cabio del sistea. i la clase @l se considera totalente lógica, no debeos reocuaos or searar las resonsabilidades. i no necesitaos #uncionalidad de actuali!ación en el #uturo, odeos ol6idaos de @l. /ero si teneos @ue abrir una clase, debeos corregir el dise3o. HE si otaos or una solución coo la del Listado 010I Los étodos ;blicos de inter#a! de#inidos en @l en el Listado 019 se re#actori!an en sus roias 6ariantes de la clase @l. Los étodos ri6ados, coo 6aluesList, se ue6en directaente a las osiciones necesarias. *l coortaiento ri6ado se reduce a un ar de clases de utilidad: 7%ere 5 ColunList. !istado
n gruo de clases cerradas. (bstract ublic class @l _`Ob ublic @ltring table, ColunU coluns4 abstract ublic tring generate4 _`Od ublic class Create@l e>tends @l _`Ob ublic Create@ltring table, ColunU coluns4 [<6erride ublic tring generate4 _`Od ublic class elect@l e>tends @l _`Ob ublic elect@ltring table, ColunU coluns4 [<6erride ublic tring generate4 _`Od ublic class "nsert@l e>tends @l _`Ob ublic elect@ltring table, ColunU coluns, tends @l _`Ob ublic elect7it%Criteria@l tring table, ColunU coluns, Criteria criteria4 [<6erride ublic tring generate4 _`Od ublic class elect7it%Matc%@l e>tends @l _`Ob ublic elect7it%Matc%@l
tring table, ColunU coluns, Colun colun, tring attern4 [<6erride ublic tring generate4 _`Od ublic class ind)5$e5@l e>tends @l _`Ob ublic ind)5$e5@l tring table, ColunU coluns, tring &e5Colun, tring &e5alue4 [<6erride ublic tring generate4 _`Od ublic class /reared"nsert@l e>tends @l _`Ob ublic /reared"nsert@ltring table, ColunU coluns4 [<6erride ublic tring generate4 ri6ate tring lace%olderListColunU coluns4 _`Od ublic class 7%ere _`Ob ublic 7%eretring criteria4 ublic tring generate4 _`Od ublic class ColunList _`Ob ublic ColunListColunU coluns4 ublic tring generate4 _`Od *l código de cada clase se sili#ica enoreente. *l tieo necesario ara entender las clases se reduce al ínio. *l riesgo de @ue una #unción a#ecte a otra desaarece casi or coleto. -esde el unto de 6ista de las ruebas, resulta =s sencillo robar la lógica de esta solución, 5a @ue las clases se aíslan unas de otras. (de=s, cuando llegue el oento de a3adir las instrucciones udate, no cabia ninguna de las clases e>istentes. (3adios la lógica ara generar instrucciones udate a una nue6a subclase de @l, date@l. *ste cabio no a#ecta a otro código del sistea. Buestra lógica @l reestructurada reresenta lo e8or de abos undos. Cule con R/ 5 tabién con otro rinciio cla6e del dise3o de clases orientadas a ob8etos, denoinado /rinciio abiertoQcerradoVAU: las clases deben abrirse ara su aliación ara cerrarse ara su odi#icación. La nue6a clase @l se abre a nue6as #uncionalidades ediante la creación de subclases ero odeos reali!ar estos cabios 5 antener cerradas las de=s clases. )asta con a3adir nuestra clase date@l. -ebeos estructurar nuestros sisteas ara ensuciarlos lo enos osible cuando los actualiceos con nue6as #unciones o cabios. *n un sistea ideal, incororaos nue6as #unciones ali=ndolo, no odi#icando el código e>istente.
Aislarnos de los cambios Las necesidades cabiar=n 5 tabién lo %ar= el código. *n la rograación orientada a ob8etos arendeos @ue %a5 clases concretas @ue contienen detalles de ileentación el código4 5 clases abstractas @ue sólo reresentan concetos. na clase cliente @ue deenda de detalles concretos est= en eligro si dic%os detalles cabian. /odeos recurrir a inter#aces 5 clases abstractas ara aislar el iacto de dic%os detalles. Las deendencias de detalles de concretos crean retos ara nuestro sistea. i
teneos @ue crear la clase /ort#olio 5 ésta deende de una (/" To&5otoc&*>c%ange e>terna ara obtener su 6alor, nuestros casos de rueba se 6er=n a#ectados or la 6olatilidad de esta b;s@ueda. Resulta colicado crear una rueba cuando se obtiene una resuesta di#erente cada cinco inutos. *n lugar de dise3ar /ort#olio ara @ue deenda directaente de To&5otoc&*>c%ange, creaos una inter#a!, toc&*>c%ange, @ue declara un ;nico étodo: ublic "nter#ace toc&*>c%ange _`Ob Mone5 current/ricetring s5bol4 _`Od -ise3aos To&5otoc&*>c%ange ara ileentar esta inter#a!. Tabién nos aseguraos de @ue el constructor de /ort#olio adote coo arguento una re#erencia a toc&*>c%ange: ublic /ort#olio _`Ob ri6ate toc&*>c%ange e>c%ange ublic /ort#oliotoc&*>c%ange e>c%ange4 _`Ob t%is.e>c%ange X e>c%ange _`Od QQY _`Od (%ora la rueba uede crear una ileentación de la inter#a! toc&*>c%ange @ue eule To&5otoc&*>c%ange. *sta ileentación de rueba #i8ar= el 6alor actual del síbolo @ue useos en la rueba. i nuestra rueba deuestra la ad@uisición de cinco acciones de Microso#t ara nuestra cartera de 6alores, dise3e el código de la ileentación de rueba ara @ue siere de6uel6a 00 dólares or acción de Microso#t. Buestra ileentación de rueba de la inter#a! toc&*>c%ange se reduce a una sencilla b;s@ueda de tabla. -e este odo odeos crear una rueba @ue esere un 6alor de cartera carter a total de 00 dólares: ublic class /ort#olioTest _`Ob ri6ate i>edtoc&*>c%angetub e>c%ange ri6ate /ort#olio ort#olio [)e#ore rotected 6oid set4 t%ro?s *>cetion _`Ob e>c%ange X ne? i>edtoc&*>c%angetub4 e>c%ange.#i>MT, 004 ort#olio X ne? /ort#olioe>c%ange4 _`Od [Test ublic 6oid Gi6eni6eMTTotal%ould)e004 t%ro?s *>cetion _`Ob ort#olio.add, MT4 (ssert.assert*@uals00, ort#olio.6alue44 _`Od _`Od i diseccionaos un sistea ara oder robarlo de esta #ora, resultar= =s #le>ible 5 se odr= reutili!ar. La ausencia de cone>iones signi#ica @ue los eleentos del sistea se aíslan entre ellos 5 de otros cabios. *ste aislaiento %ace @ue corendaos e8or los eleentos del sistea. (l inii!ar las cone>iones de esta #ora, nuestras clases culen otro rinciio
de dise3o: Dependenc. 3nversion Principle -"/4 o /rinciio de in6ersión de deendenciasV9U. )=sicaente a#ira @ue nuestras clases deben deender de abstracciones, no de detalles concretos. *n lugar de deender de los detalles de ileentación de la clase To&5otoc&*>c%ange, nuestra clase /ort#olio deende de la inter#a! toc&*>c%ange, @ue reresenta el conceto abstracto de solicitar el recio actual de una acción. *sta abstracción aísla todos los datos concretos de la obtención de dic%o recio, inclu5endo de dónde se obtiene.
(ibliograf:a ;422>: b0ect Design: oles, esponsibilities, and Collaborations, Rebecca 7ir#s1 )roc& et al., (ddison17esle5, 2002. ;PPP>: Agile Software Development: Principles, Patterns, and Practices, Robert C. Martin, /rentice all, 2002. ;?nut/@>: 'iterate Programming , -onald *. $nut%, Center #or t%e tud5 o# language and "n#oration, Leland tan#ord Junior ni6ersit5, 992.
Sistemas or el -r. $e6in -ean 7aler
E'a comple0idad es letal" Acaba con los desarrolladores . dific%lta la planificaci2n, generaci2n . pr%ebas de los prod%ctosF"
\4a- Ozzie* C3O* Microsoft Corporation
Cómo construir una ciudad H/odría encargarse de todos los detalles or su cuentaI eguraente no. "ncluso la
gestión de una ciudad e>istente sería deasiado ara una sola ersona. E aun así, las ciudades #uncionan en la a5oría de los casos4. uncionan or@ue tienen e@uios @ue controlan artes concretas de la ciudad, el alcantarillado, la red eléctrica, el tr=#ico, la seguridad, las norati6as urbanísticas, etc. (lgunos se encargan de asectos generales 5 otros se centran en los detalles. Las ciudades tabién #uncionan or@ue disonen de e6olucionados ni6eles de abstracción 5 odularidad @ue eriten a indi6iduos 5 coonentes traba8ar de #ora e#ica!, sin necesidad de entender el tras#ondo general. (un@ue los e@uios de software se suelen organi!ar de esta #ora, los sisteas en los @ue traba8an no suelen contar con la isa searación de asectos 5 ni6eles de abstracción. *n este caítulo 6ereos cóo antener la liie!a en ni6eles sueriores de abstracción, en el sistea.
Separar la construcción de un sistema de su uso *n rier lugar, recuerde @ue la construcción es un roceso u5 di#erente al uso. Mientras escribo estas líneas, a tra6és de la 6entana 6eo un nue6o %otel en construcción en C%icago. o5 instalar=n una gran gr;a. Todos los obreros lle6an casco. -entro de un a3o %abr=n acabado el %otel. La gr;a desaarecer=. *l edi#icio estar= terinado, con su reluciente #ac%ada de cristal 5 su atracti6a decoración. La gente @ue traba8ar= en él tabién ser= di#erente. 'os sistemas de software deben separar el proceso de inicio, en el *%e se crean los ob0etos de la aplicaci2n . se conectan las dependencias, de la l2gica de e0ec%ci2n *%e toma el testigo tras el inicio"
*l roceso de inicio es un asecto @ue toda alicación debe abordar. *s el riero @ue 6ereos en este caítulo. La searación de asectos es una de las técnicas de dise3o =s antiguas e iortantes de nuestra ro#esión. -esa#ortunadaente, uc%as alicaciones no lo %acen. *l código del roceso de inicio se e!cla con la lógica de tieo de e8ecución. eaos un e8elo tíico: ublic er6ice geter6ice4 _`Ob i# ser6ice XX null4 ser6ice X ne? M5er6ice"l Y4 QQHLo bastante redeterinado ara la a5oría de los casosI return ser6ice _`Od *s la técnica de iniciali(aci2neval%aci2n tard+a 5 tiene sus éritos. Bo incurrios en la sobrecarga de la construcción a enos @ue useos el ob8eto realente, 5 coo resultado el tieo de inicio se uede acelerar. Tabién e6itaos @ue se de6uel6a null. in ebargo, a%ora teneos una deendencia en M5er6ice"l 5 todo lo @ue su constructor re@uiere @ue %e oitido4. Bo odeos coilar sin resol6er estas deendencias, aun@ue nunca useos un ob8eto de este tio en tieo de e8ecución. Las ruebas tabién ueden ser un roblea. i M5er6ice"l es un ob8eto esado, tendreos @ue aseguraos asegur aos de asignar el corresondiente test do%ble0U u ob8eto siulado al cao de ser6icio antes de in6ocar este étodo en las ruebas de unidad. Coo la lógica de la construcción se e!cla con el rocesaiento noral de tieo de
e8ecución, debeos robar todas las rutas de e8ecución coo la rueba null 5 su blo@ue4. (l contar con abas resonsabilidades, el étodo %ace =s de una cosa, or lo @ue se incule el rinciio de resonsabilidad ;nica. Lo eor de todo es @ue no sabeos si M5er6ice"l es el ob8eto correcto en todos los casos. H/or @ué la clase con este étodo tiene @ue conocer el conte>to globalI H/odeos saber realente cu=l es el ob8eto correcto @ue usar a@uíI H*s osible @ue un iso tio sea el correcto ara todos los conte>tos osiblesI n caso de iniciali(aci2n tard+a no es un roblea serio. in ebargo, suele %aber uc%os casos de este tio de con#iguración en las alicaciones. /or tanto, la estrategia de con#iguración global si e>iste4 se diseina or la alicación, sin aenas odularidad 5 con una signi#icati6a dulicación. i soos diligentes sobre el dise3o de sisteas robustos 5 bien #orados, no debeos eritir #allos de odularidad. *l roceso de inicio de la construcción 5 cone>ión de ob8etos no es una e>ceción. -ebeos odulari!ar este roceso 5 aseguraos de contar con una estrategia global 5 co%erente ara resol6er las deendencias rinciales.
Separar Main na #ora de searar la construcción del uso consiste en trasladar todos los asectos de la construcción a ain o a ódulos in6ocados or ain, 5 dise3ar el resto del sistea suoniendo @ue todos los ob8etos se %an creado 5 conectado correctaente 6éase la #igura .4. *l #lu8o de control es #=cil de seguir. La #unción ain crea los ob8etos necesarios ara el sistea, los asa a la alicación 5 ésta los utili!a. er= @ue las #lec%as de deendencia atra6iesan la barrera entre ain 5 la alicación. Todas 6an en la isa dirección, ale8=ndose de ain, lo @ue signi#ica @ue la alicación no tiene conociiento de ain ni del roceso de construcción. ileente esera @ue todo se %a5a construido correctaente.
igura .. earación de la construcción en ain4.
$actor:as *n ocasiones, la alicación tendr= @ue ser resonsable de la creación de un ob8eto. /or e8elo, en un sistea de rocesaiento de edidos, la alicación debe crear las instancias Line"te @ue a3adir a treo ain de la línea. E sin ebargo, la alicación tiene control total sobre cu=ndo se crean las instancias Line"te e incluso uede roorcionar arguentos de constructor esecí#icos de la alicación.
igura .2. earación de la construcción con una #actoría.
In-ectar dependencias n otente ecaniso ara searar la construcción del uso es la "n5ección de deendencias, la alicación de "n6ersión de control 3nversion 3nversion of Control o o "oC4 a la 2U adinistración de deendencias . La "n6ersión de control asa resonsabilidades secundarias de un ob8eto a otros dedicados a ese coetido, or lo @ue adite el rinciio de resonsabilidad ;nica. *n el conte>to de la adinistración de deendencias, un ob8eto no debe ser resonsable de instanciar deendencias, sino @ue debe delegar esta resonsabilidad en otro ecaniso autori!ado, de odo @ue se in6ierte el control. Coo la con#iguración es un asecto global, este ecaniso autori!ado suele ser la rutina ain o un contenedor de roósito esecial. Las b;s@uedas JB-" son una ileentación arcial de la in5ección de deendencias, en las @ue un ob8eto solicita a un ser6idor de directorios un ser6icio @ue
coincida con un nobre concreto. M5er6ice 5er6ice X M5er6ice48ndiConte>t.loo&uBae<#M5er6ice44 M5er6ice48ndiConte>t.loo&uBae<#M5er6ice44 *l ob8eto in6ocador no controla el tio de ob8eto de6uelto siere @ue ileente la inter#a! correcta, e6identeente4, ero es el @ue resuel6e la deendencia de #ora acti6a. La 6erdadera in5ección de deendencias 6a un aso =s all=. La clase no %ace nada directaente ara resol6er sus deendencias, es totalente asi6a. /or el contrario, o#rece étodos de estableciiento o arguentos de constructor o abos4 @ue se usan ara in5ectar las deendencias. *n el roceso de construcción, el contenedor de in5ección de deendencias crea instancias de los ob8etos necesarios noralente ba8o deanda4 5 usa los arguentos de constructor o étodos de estableciiento roorcionados ara conectar las deendencias. Los ob8etos deendientes eleados suelen eseci#icarse a tra6és de un arc%i6o de con#iguración o ediante rograación en un ódulo de construcción de roósito esecial. La estructura ring roorciona el contenedor de in5ección de deendencias =s conocido ara Ja6aWU. Los ob8etos @ue se 6an a conectar se de#inen en un arc%i6o de con#iguración +ML 5 desués se solicitan ob8etos concretos or nobre en código de Ja6a. ereos un e8elo en bre6e. HE @ué sucede con las 6irtudes de la iniciali!ación tardíaI *n ocasiones es ;til con la in5ección de deendencias. /or un lado, uc%os contenedores de in5ección de deendencias no crean un ob8eto %asta @ue es necesario. /or otra arte, uc%os de estos contenedores cuentan con ecanisos ara in6ocar #actorías o crear ro>ies @ue se ueden usar ara e6aluación tardía 5 otii!aciones siilaresVU.
#+olucionar Las ciudades nacen de ueblos, @ue nacen de asentaientos. "nicialente, los cainos son estrec%os 5 r=cticaente ine>istentes, desués se as#altan 5 auentan de taa3o. Los e@ue3os edi#icios 5 solares 6acíos se llenan de otros a5ores @ue acaban con6irtiéndose en rascacielos. (l rinciio no %a5 ser6icios, electricidad, agua, alcantarillado o "nternet f6a5a4. *stos ser6icios se a3aden cuando auenta la densidad de oblación. *ste creciiento no es #=cil. Cu=ntas 6eces ientras conduce or una carretera llena de bac%es 5 6e una se3al de obras no se %a reguntado or @ué no la %icieron =s anc%a desde un rinciio. Bo se odía %aber %ec%o de otra #ora. HKuién uede 8usti#icar el gasto en una autoista de seis carriles @ue atra6iese un e@ue3o ueblo coo anticiación a un suuesto creciientoI HKuién @uerría una autoista así en su ciudadI Conseguir sisteas er#ectos a la riera es un ito. /or el contrario, debeos ileentar %o5, 5 re#actori!ar 5 aliar a3ana. *s la esencia de la agilidad iterati6a e increental. *l desarrollo controlado or ruebas, la re#actori!ación 5 el código liio @ue generan %ace @ue #uncione a ni6el del código. H/ero @ué sucede en el ni6el del sisteaI HLa ar@uitectura del sistea no re@uiere una lani#icación re6iaI in duda no uede auentar increentalente algo sencillo a algo cole8o, Ho síI 'os sistemas de software son 8nicos si los los comparamos con los sistemas f+sicos" S%s
ar*%itect%ras p%eden crecer incrementalmente, si mantenemos la co rrecta separaci2n de los aspectos"
La naturale!a e#íera de los sisteas de software %ace @ue sea osible, coo 6ereos. /riero nos centrareos en una ar@uitectura @ue no seara correctaente los asectos. Las ar@uitecturas *J) 5 *J)2 originales no searaban correctaente los asectos 5 or tanto ionían barreras innecesarias al creciiento org=nico. "agine un bean de entidad ara una clase )an& ersistente. ersistente. n bean de entidad es una reresentación reres entación en eoria de datos relaciónales, es decir, una #ila de una tabla. /riero, debe de#inir una inter#a! local en roceso4 o reota MJ indeendiente4, @ue los clientes usen. *l Listado 1 uestra una osible inter#a! local: !istado F na inter#a! local *J)2 ara el *J) )an&. ac&age co.e>ale.ban&ing iort 8a6a.util.Collections iort 8a6a>.e8b. ublic inter#ace )an&Local e>tends 8a6a.e8b.*J)Localcetion tring gettreet(ddr2_`Ob_`Od t%ro?s *J)*>cetion tring getCit54 t%ro?s *J)*>cetion tring gettate4 t%ro?s *J)*>cetion tring getDiCode4 t%ro?s *J)*>cetion 6oid settreet(ddrtring street4 t%ro?s *J)*>cetion 6oid settreet(ddr2tring street24 t%ro?s *J)*>cetion 6oid setCit5tring cit54 t%ro?s *J)*>cetion 6oid settatetring state4 t%ro?s *J)*>cetion 6oid setDiCodetring !i4 t%ro?s *J)*>cetion Collection get(ccounts4 t%ro?s *J)*>cetion 6oid set(ccountsCollection accounts4 t%ro?s *J)*>cetion 6oid add(ccount(ccount-T< account-T<4 t%ro?s *J)*>cetion _`Od Mostraos di6ersos atributos de la dirección de )an& 5 una colección de cuentas del banco, cu5os datos se rocesar=n or un *J) (ccount di#erente. *l Listado 12 uestra la corresondiente clase de ileentación del bean )an&. !istado . "leentación del bean de entidad *J)2. ac&age co.e>ale.ban&ing iort 8a6a.util.Collections iort 8a6a>.e8b. ublic abstract class )an& ileents 8a6a>.e8b.*ntit5)ean _`Ob QQ Lógica eresarialY ublic abstract tring gettreer(ddr4 ublic abstract tring gettreet(ddr24 ublic abstract tring getCit54 ublic abstract tring gettate4
ublic abstract tring getDiCode4 ublic abstract 6oid settreet(ddrtring street4 ublic abstract 6oid settreet(ddr2tring street24 ublic abstract 6oid setcit5tring cit54 ublic abstract 6oid settatetring state4 ublic abstract 6oid setDiCodetring !i4 ublic abstract Collection get(ccounts4 ublic abstract 6oid set(ccountsCollection accounts4 ublic 6oid add(ccount(ccount/T< account-T<4 "nitialConte>t conte>t X ne? "nitialConte>t4 (ccountoeLocal accountoe X conte>t.loo&u(ccountoeLocal4 (ccountLocal account X accountoe.createaccount-T<4 Collection accounts X get(ccounts4 accounts.addaccount4 _`Od QQ Lógica del contenedor *J) ublic abstract 6oid set"d"nteger id4 ublic abstract "nteger get"d4 ublic "nteger e8bCreate"nteger id4 _`ObY _`Od ublic 6oid e8b/ostCreate"nteger id4 _`ObY _`Od QQ *l resto tendría @ue ileentarse ero se de8a 6acío: ublic 6oid set*ntit5Conte>t*ntit5Conte>t ct>4 _`Ob_`Od ublic 6oid unset*ntit5Conte>t4 _`Ob_`Od ublic 6oid e8b(cti6ate4 _`Ob_`Od ublic 6oid e8b/assi6ate4 _`Ob_`Od ublic 6oid e8bLoad4 _`Ob_`Od ublic 6oid e8btore4 _`Ob_`Od ublic 6oid e8bReo6e4 _`Ob_`Od _`Od Bo ostraos la corresondiente inter#a! Localoe, b=sicaente una #actoría usada ara crear ob8etos, no los étodos de consulta )an& @ue ueda a3adir. /or ;ltio, debeos crear uno o 6arios descritores de ileentación +ML @ue eseci#i@uen los detalles de asignación relacional de ob8etos en un alacén ersistente, el coortaiento deseado de la transacción, liitaciones de seguridad 5 de=s. La lógica eresarial est= directaente conectada al contenedor de la alicación *J)2. -ebe crear subclases de tios de contenedor 5 roorcionar los étodos de ciclo 6ital necesarios ara el contenedor. -ebido a esta cone>ión al contenedor esado, las ruebas de unidad aisladas son colicadas. co licadas. *s necesario iitar el contenedor, algo di#ícil, o erder deasiado tieo en la ileentación de *J) 5 ruebas en un ser6idor real. La reutili!ación #uera de la ar@uitectura *J)2 es iosible, debido a esta estrec%a cone>ión. /or ;ltio, incluso la rograación orientada a ob8etos se 6e a#ectada. n bean no se uede %eredar de otro. í8ese en la lógica ara ara a3adir una nue6a cuenta. *n bean b ean *J)2 es %abitual de#inir
Aspectos trans+ersales La ar@uitectura *J)2 se acerca a la 6erdadera searación de asectos en deterinados asectos. /or e8elo, los coortaientos transaccionales, de seguridad 5 coortaiento deseados se declaran en los descritores de ileentación, indeendienteente del código #uente. (sectos coo la ersistencia suelen cru!ar los líites de ob8eto naturales de un doinio. /or lo general intentar= antener todos sus ob8etos ediante la isa estrategia, or e8elo con un deterinado -)MU 5 no arc%i6os lanos, usando deterinadas con6enciones de noenclatura ara tablas 5 colunas, una se=ntica transaccional co%erente, etc. *n rinciio, uede ra!onar su estrategia de ersistencia de una #ora odular 5 encasulada, ero en la r=ctica tendr= @ue distribuir el iso código @ue ileente la estrategia de ersistencia entre 6arios ob8etos. saos el térino trans6ersales ara este tio de asectos. -e nue6o, la estructura de ersistencia odría ser odular 5 la lógica de doinios, aislada, tabién. *l roblea es la intersección entre abos doinios. -e %ec%o, la #ora en @ue la ar@uitectura *J) rocesa ersistencia, seguridad 5 transacciones es una /rograación orientada a asectos Aspect Aspect riented Programming o o NU (4 anticiada, un en#o@ue de car=cter general ara restaurar la odularidad en asectos trans6ersales. *n (, construcciones odulares denoinadas asectos eseci#ican @ué untos del sistea deben odi#icar su coortaiento de #ora co%erente ara aditir un deterinado asecto. *sta eseci#icación eseci# icación se reali!a ediante un sucinto ecaniso de declaración o rograación. i usaos la ersistencia coo e8elo, odría declarar @ué ob8etos 5 atributos o atrones4 deben conser6arse conser6 arse 5 desués delegar las tareas de ersistencia a su estructura de ersistencia. Las odi#icaciones de coortaiento no son s on in6asi6asOU ara el código de destino. eaos tres asectos o ecanisos siilares en Ja6a.
ProEies de Ja+a Los ro>ies de Ja6a son ;tiles en casos sencillos, coo en6ol6er in6ocaciones de étodos en ob8etos o clases concretas. in ebargo, los ro>ies din=icos roorcionados en el J-$ sólo #uncionan con inter#aces. /ara alicarlos a clases, debe usar una biblioteca de aniulación de código de b.tes, coo CGL"), (M o Ja6assistAU. *l Listado 1W uestra la estructura de un ro>5 J-$ ara o#recer asistencia de ersistencia a nuestra alicación )an& ;nicaente abarca abar ca los étodos ara obtener 5 establecer la lista de cuentas. !istado FG *8elo de ro>5 del J-$. QQ )an&.8a6a eliinando nobres de a@uetesY4 iort 8a6a.utils. QQ La abstracción de un banco. ublic inter#ace )an& _`Ob Collection](ccount^ get(ccounts4 6oid set(ccountsCollection](ccounts^ accounts4
_`Od QQ )an&"l.8a6a iort 8a6a.utils. QQ /lain 5andler.8a6a iort 8a6a.lang.re#lect. iort 8a6a.util. QQ F"n6ocationandler necesario ara la (/" de ro>5. ublic class )an&/ro>5andler ileents "n6ocationandler _`Ob ri6ate )an& ban& ublic )an&andler )an& ban&4 _`Ob t%is.ban& X ban& _`Od QQ Método de#inido en "n6ocationandler ublic 5, Met%od et%od, 5.ne?ro>5"nstance )an&.class.getClassLoader4,
ne? ClassU _`Ob )an&.class _`Od, ne? )an&/ro>5andlerne? )an&"l444 -e#inios la inter#a! )an&, @ue en6ol6eos en el ro>5 5 un /5 re@uiere un ob8eto "n6ocationandler @ue in6ocar ara ileentar las in6ocaciones de étodos )an& reali!adas en el ro>5. )an&/ro>5andler usa la (/" de re#le>ión de Ja6a ara asignar las in6ocaciones de étodos genéricos a los étodos corresondientes de )an&"l, 5 así sucesi6aente. *l código es abundante 5 cole8o, incluso ara este sencillo caso9U. *l uso de una de las bibliotecas de aniulación de b.tes es igualente colicado. *l 6oluen 5 la cole8idad de este código son dos de los incon6enientes de los ro>ies. -i#icultan la creación de código liio. (de=s, los ro>ies no o#recen un ecaniso ara eseci#icar untos de e8ecución globales del sistea, irescindibles ara una u na 6erdadera solución N0U ( .
#structuras AOP Ja+a puras (#ortunadaente, gran arte del código rede#inido de ro>5 se uede rocesar de #ora auto=tica ediante %erraientas. Los ro>ies se usan internaente en 6arias estructuras de Ja6a coo ring ( 5 J)oss (, ara ileentar asectos en Ja6aNU. *n ring, se crea la lógica eresarial en #ora de /ies de Ja6a o bibliotecas de código de b.tes de #ora transarente al usuario. *stas declaraciones controlan el contenedor de in5ección de deendencias, @ue crea instancias de los rinciales ob8etos 5 las conecta ba8o deanda. *l Listado 1V uestra un #ragento tio de un arc%i6o de con#iguración de ring 2., a.>lN2U. !istado .
(rc%i6o de con#iguración de ring 2.+ ]beans^ Y ]bean idXa-ataource classXorg.aac%e.coons.dbc.)asic-ataource destro51et%odXclose :dri6erClassBaeXco.[email protected] :urlX8dbc:5s@l:QQlocal%ost:WW0NQ5db :usernaeXeQ^
]bean idXban&-ata(ccessale.ban&ing.ersistence.)an&-ata(ccessale.ban&ing.odel.)an& :data(ccess5 )an& en6uelto4 or un 5 or edio de un origen de datos de controlador J-)C 6éase la #igura .W4.
igura .W. La u3eca rusa de eleentos de decoración. *l cliente cree @ue in6oca get(ccounts4 en un ob8eto )an&, ero en realidad se counica con el ob8eto -*Cterno de un gruo, un ob8eto @ue alía el coortaiento b=sico del /l, getclass444 )an& ban& X )an&4 b#.get)eanban&4 Coo aenas se necesitan líneas de código Ja6a esecí#ico de ring, la alicación se desconecta casi or coleto de ring 5 desaarecen los robleas de cone>ión de sisteas coo *J)2. (un@ue +ML uede ser di#ícil de leer NVU, la directi6a eseci#icada en estos arc%i6os de con#iguración es =s sencilla @ue la colicada lógica de ro>5 5 asectos oculta a la 6ista 5 creada de #ora auto=tica. *s una ar@uitectura tan atracti6a @ue sisteas coo ring odi#icaron totalente el est=ndar *J) ara la 6ersión W. *J)W sigue el odelo de ring de asectos trans6ersales aditidos ediante declaraciones con arc%i6os de con#iguración +ML 5Qo anotaciones de Ja6a . *l Listado 1 uestra nuestro ob8eto )an& reescrito en *J)WNU. !istado F n *J) )an& *)JW. ac&age co.e>ale.ban&ing.odel iort 8a6a>.ersistence iort 8a6a.util.(rra5List
iort 8a6a.util.Collection [*ntit5 [Tablenae X )(B$4 ublic class )an& ileents 8a6a.io.eriali!able _`Ob ["d [Generatedaluestrateg5XGenerationT5e.(T<4 ri6ate int id [*beddable QQ n ob8eto en línea en la #ila -) de )an& ublic class (ddress _`Ob rotected tring street(ddr rotected tring street(ddr2 rotected tring cit5 rotected tring state rotected tring !iCode _`Od [*bedded ri6ate (ddress address [
Aspectos de AspectJ /or ;ltio, la %erraienta =s coleta de searación a tra6és de asectos es el lengua8e (sectJNNU, una e>tensión de Ja6a @ue o#rece coatibilidad de rier ni6el ara asectos coo construcciones de odularidad. Los en#o@ues uros de Ja6a roorcionados or ring ( 5 J)oss ( son su#icientes en el A0190 or 00 de los casos en e n los @ue los asectos son ;tiles. in ebargo, (sectJ o#rece un con8unto de %erraientas a6an!adas 5 coletas ara la searación de asectos. *l incon6eniente de (sectJ es la necesidad de adotar nue6as %erraientas 5 arender nue6as construcciones del lengua8e. Los robleas de adoción se %an itigado arcialente gracias a la introducción de un #orato de anotación de (sectJ, en el @ue se usan anotaciones de Ja6a ara de#inir asectos con código uro de Ja6a. (de=s, la estructura ring disone de #unciones @ue #acilitan la incororación de asectos basados en anotaciones en un e@uio con e>eriencia liitada con (sectJ. *l an=lisis coleto de (sectJ suera los ob8eti6os de este libro. i necesita =s in#oración al resecto, consulte (sectJU, Col5erU 5 ringU.
Pruebas de unidad de la ar9uitectura del sistema La searación a tra6és de en#o@ues siilares a asectos no se uede enosreciar. i uede crear la lógica de doinios de su alicación ediante /ión con los asectos ar@uitectónicos a ni6el del código, entonces se odr= robar realente la ar@uitectura. /uede e6olucionar de sile a so#isticado, de acuerdo a las necesidades, adotando nue6as tecnologías ba8o deanda. Bo es necesario reali!ar un =%en diseo por adelantado )ig -esign rontNOU, )-4. -e %ec%o, )- uede ser negati6o 5a @ue iide la adatación al cabio, debido a la resistencia #isiológica a descartar es#uer!os re6ios 5 a la #ora en @ue las decisiones dec isiones ar@uitectónicas in#lu5en en la conceción osterior del dise3o. Los ar@uitectos deben reali!ar )- 5a @ue no resulta #actible alicar cabios ar@uitectónicos radicales a una estructura #ísica una 6e! a6an!ada la construcciónNAU. (un@ue el software se rige or una #ísica roiaN9U, es econóicaente #actible reali!ar cabios radicales si la estructura del software seara sus asectos de #ora e#ica!. *sto signi#ica @ue odeos iniciar un ro5ecto de software con una ar@uitectura sile ero bien desconectada, 5 o#recer %istorias #uncionales de #ora r=ida, ara desués auentar la in#raestructura. (lgunos de los rinciales sitios 7eb del undo %an alcan!ado una gran disonibilidad 5 rendiiento or edio de so#isticadas técnicas de alacenaiento en cac%é, seguridad, 6irtuali!ación 5 de=s, todo ello de #ora e#ica! 5 #le>ible 5a @ue los dise3os íniaente conectados son adecuadaente siles en cada ni6el de abstracción 5 =bito. *6identeente, no @uiere decir @ue acoetaos los ro5ectos sin tión. -ebeos tener e>ectati6as del =bito general, genera l, ob8eti6os 5 un rograa, así coo la estructura general gener al del sistea resultante. in ebargo, debeos antener la caacidad de cabiar de rubo en resuesta a las circunstancias. La ar@uitectura *J) inicial es una de las (/" conocidas con un e>ceso de ingeniería 5 @ue coroete la searación de asectos. "ncluso las (/" bien dise3adas ueden ser e>cesi6as cuando no resultan necesarias. na (/" correcta debe desaarecer de la 6ista en
la a5oría de los casos, ara @ue el e@uio dedi@ue sus es#uer!os creati6os a las %istorias ileentadas. *n caso contrario, las liitaciones ar@uitectónicas iedir=n la entrega e#ica! de un 6alor ótio ara el cliente. /ara recaitular: na ar*%itect%ra de sistema 2ptima se compone de dominios de aspectos mod%lari(ados, cada %no implementado con PJ" 'os distintos dominios se integran mediante aspectos o herramientas similares m+nimamente invasivas" Al ig%al *%e en el c2digo, en esta ar*%itect%ra se p%eden reali(ar pr%ebas"
Optimizar la toma de decisiones La odularidad 5 searación de asectos erite la descentrali!ación de la adinistración 5 la toa de decisiones. *n un sistea su#icienteente alio, 5a sea una ciudad o un ro5ecto de software, no debe %aber una sola ersona @ue adote todas las decisiones. abeos @ue con6iene delegar las resonsabilidades en las ersonas =s cuali#icadas. oleos ol6idar @ue tabién con6iene osoner decisiones %asta el ;ltio oento. Bo es #alta de resonsabilidad nos erite toar decisiones con la e8or in#oración osible. na decisión reatura siere es sub8eti6a. i decidios deasiado ronto, tendreos enos in#oración del cliente, re#le>ión re# le>ión ental sobre el ro5ecto 5 e>eriencia con las ociones de ileentación. 'a agilidad *%e proporciona %n sistema PJ con aspectos mod%lari(ados nos permite adoptar decisiones 2ptimas a tiempo, basadas en los conocimientos m#s recientes" Adem#s, se red%ce la comple0idad de estas decisiones"
8sar estándares cuando a%adan un +alor demostrable La construcción de edi#icios es una ara6illa ara la 6ista debido al rito eleado incluso en in6ierno4 5 los e>traordinarios dise3os osibles gracias a la tecnología actual. La construcción es un sector aduro con eleentos, étodos 5 est=ndares otii!ados @ue %an e6olucionado ba8o resión durante siglos. Muc%os e@uios usaron la ar@uitectura *J)2 or ser un est=ndar, aun@ue %ubiera bastado con dise3os =s ligeros 5 sencillos. sen cillos. e 6isto e@uios obsesionados con est=ndares de oda 5 @ue se ol6idaron de ileentar el 6alor ara sus clientes. 'os est#ndares facilitan la re%tili(aci2n re%tili(aci2n de ideas . componentes, recl%tan individ%os con e9periencia, encaps%lan b%enas ideas . conectan componentes" Sin embargo, el proceso de creaci2n de est#ndares p%ede tardar demasiado para el sector, . alg%nos pierden el contacto con las verdaderas necesidades de a*%ello para los *%e est#n dirigidos"
!os sistemas necesitan lengua)es espec:ficos del dominio La construcción de edi#icios, coo uc%os doinios, %a desarrollado un rico
lengua8e con 6ocabularios, #rases 5 atronesO0U @ue counican in#oración esencial de #ora clara 5 concisa. *n el undo del software, %a renacido el interés or crear Lengua8es esecí#icos del doinio Domain-Specific Domain-Specific 'ang%ages o -L4OU, e@ue3os lengua8es indeendientes de creación de secuencias de coandos o (/" de lengua8es est=ndar @ue eriten crear código @ue se lea de una u na #ora estructurada, coo lo escribiría un e>erto e> erto del doinio. n buen -L inii!a el 6acío de counicación entre un conceto de doinio 5 el código @ue lo ileenta, al igual @ue las r=cticas =giles otii!an la counicación entre un e@uio 5 los accionistas del ro5ecto. i tiene @ue ileentar la lógica de doinios en el iso lengua8e usado or un e>erto del doinio, %a5 enos riesgo de traducir incorrectaente el doinio en la ileentación. Los -L, si se usan de #ora e#ica!, auentan el ni6el de abstracción or encia del código 5 los atrones de dise3o. /eriten al desarrollador re6elar la intención del código en el ni6el de abstracción adecuado. 'os leng%a0es espec+ficos del dominio permiten e9presar como PJ todos los niveles de abstracci2n . todos los dominios de la aplicaci2n, desde directivas de nivel s%perior a los detalles m#s m+nimos"
Conclusión Los sisteas tabién deben ser liios. na ar@uitectura in6asi6a a#ecta a la lógica de doinios 5 a la agilidad. i la lógica de doinios se 6e a#ectada, la calidad se resiente, 5a @ue los errores se ocultan 5 las %istorias son =s di#íciles de ileentar. i la agilidad se 6e coroetida, la roducti6idad su#re 5 las 6enta8as de T-- se ierden. *n todos los ni6eles de abstracción, los ob8eti6os deben ser claros. *sto sólo sucede si crea /
(ibliograf:a ;AleEander>: C%risto%er (le>ander, A $imeless a. of =%ilding , <>#ord ni6ersit5 /ress, Be? Eor&, 9O9. ;AOS2>: /uerto de -esarrollo de software orientado a asectos, %tt:QQaosd.net. ;ASM>: /=gina de (M, %tt:QQas.ob8ect?eb.orgQ. ;AspectJ>: %tt: QQeclise.orgQasect8. ;C!I(>: )iblioteca de generación de código, %tt:QQcglib.source#orge.netQ. ;Col-er>: (drian Col5er, (nd5 Cleent, George urle5, Mat%e? 7ebster, )lipse AspectJ , /erson *ducation, "nc., er addle Ri6er, BJ, 200. ;2S!>: Lengua8e de rograación esecí#ico del doinio, %tt:QQes.?i&iedia.orgQ?i&iQLengua8eesecCW(-#icodeldoinio. ;$owler>: "n6ersión de contenedores de control 5 el atrón de in5ección de deendencias %tt:QQartin#o?ler.coQarticlesQin8ection.%tl4. ;oetz>: )rian Goet!, Java $heor. and Practice: Decorating with D.namic Pro9ies, %tt:QQ???.ib.coQde6eloer?or&sQ8a6aQlibrar5Q818t0AW0.%tl.
;Ja+assist>: /=gina de Ja6assist, %tt:QQ???.csg.is.titec%.ac.8Qc%ibaQ8a6assistQ. ;J(oss>: /=gina de J)oss, %tt: QQ8boss.org. ;JMoc6>: JMoc&: na biblioteca de ob8etos Moc& ligeros ara Ja6a, %tt:QQ8oc&.org. ;?olence>: $ennet% 7. $olence, Software ph.sics and comp%ter performance meas%rements, Proceedings of the AC& ann%al conference->ol%me 2, )oston, Massac%usetts, . 02V10V0,9O2. ;Spring>: $he Spring Kramework , %tt:QQ???.sring#rae?or&.org. ;Mezzaros<=>: nit Patterns, Gerard Me!!aros, (ddison17esle5, 200O. Software, Gaa ;O$>: Design Patterns: )lements of e%sable b0ect riented Software et al., (ddison17esle5, 99N.
#mergencia con Je## Langr
!impieza a tra+Ds de dise%os emergentes "agine @ue e>istieran cuatro sencillas reglas ara crear dise3os de calidad. "agine @ue siguiéndolas accediera a la estructura 5 al dise3o de su código 5 #acilitara la alicación de rinciios coo R/ 5 -"/. "agine @ue estas cuatro reglas #acilitaran la eergencia de dise3os de calidad. Muc%os consideraos @ue las cuatro reglas de $ent )ec& de dise3o sencilloO2U son #undaentales ara crear un software bien dise3ado. eg;n $ent, un dise3o es sencillo si cule estas cuatro reglas: *8ecuta todas las ruebas. Bo contiene dulicados. *>resa la intención del rograador. Minii!a el n;ero de clases 5 étodos. -escribireos estas reglas en orden de iortancia.
Primera regla del dise%o sencilloH #)ecutar todas las pruebas *n rier lugar, un dise3o debe generar un sistea @ue act;e de la #ora re6ista. n sistea uede tener un dise3o er#ecto sobre el ael ero si no e>iste una #ora sencilla de corobar @ue realente #unciona de la #ora eserada, el es#uer!o sobre el ael es cuestionable. n sistea inuciosaente robado 5 @ue suera todas las ruebas en todo oento se denoina sistea testable. *s una a#iración ob6ia, ero iortante. Los sisteas @ue no se ueden robar no se ueden 6eri#icar, 5 un sistea @ue no se uede 6eri#icar no debe ileentarse. (#ortunadaente, crear sisteas testables %ace @ue dise3eos clases de taa3o reducido 5 un solo coetido. Resulta =s sencillo robar clases @ue culen el R/. Cuantas =s ruebas dise3eos, =s nos acercareos a eleentos =s #=ciles de robar. /or lo tanto, %acer @ue nuestro sistea se ueda robar nos a5uda a crear e8ores dise3os. Las cone>iones rígidas di#icultan la creación de ruebas. -el iso odo, cuantas =s ruebas creeos, =s usareos rinciios coo -"/ 5 %erraientas con in5ección de deendencias, inter#aces 5 abstracción ara inii!ar dic%as cone>iones. Buestros dise3os e8orar=n toda6ía =s. *n esecial, seguir una sencilla regla @ue a#ire @ue debeos reali!ar ruebas 5 e8ecutarlas continuaente a#ecta el culiiento or arte de nuestro sistea de los rinciales ob8eti6os de la rograación orientada a ob8etos ob 8etos de ba8a cone>ión 5 ele6ada co%esión. La creación de ruebas conduce a obtener e8ores dise3os.
4eglas a del dise%o sencilloH 4efactorizar na 6e! creadas las ruebas, debeos antener liio el código 5 las clases. /ara ello, re#actori!aos el código rogresi6aente. Tras a3adir unas líneas, nos deteneos 5 re#le8aos el nue6o dise3o. Ha eeoradoI *n caso a#irati6o, lo liiaos 5 e8ecutaos las ruebas ara corobar @ue no %a5 eleentos a#ectados. 'a presencia de las pr%ebas hace *%e perdamos el miedo a limpiar el c2digo . *%e res%lte daado. *n la #ase de re#actori!ación, odeos alicar todos los asectos del dise3o de software correcto. /odeos auentar la co%esión, reducir las cone>iones, searar las reocuaciones, odulari!ar asectos as ectos del sistea, reducir el taa3o de #unciones 5 clases, clases , elegir nobres =s adecuados, etc. (@uí tabién alicaos las tres ;ltias reglas del dise3o correcto: eliinar dulicados, garanti!ar la caacidad de e>resión 5 inii!ar el n;ero de clases 5 étodos.
#liminar duplicados Los dulicados son los a5ores eneigos de un sistea bien dise3ado. uonen un es#uer!o adicional, riesgos a3adidos 5 una cole8idad a a5ores innecesaria. Los dulicados se ani#iestan de di6ersas #oras. Las líneas de código siilar ueden odi#icarse ara @ue are!can re#actori!adas, 5 %a5 otras #oras de dulicación coo la de ileentación. /or e8elo, odríaos tener dos étodos en una clase de colección:
int si!e4 _`Ob_`Od boolean is*t54 _`Ob_`Od /odríaos tener ileentaciones searadas ara cada étodo. *l étodo is*t5 odría controlar un 6alor booleano 5 si!e s i!e un contador, o odeos eliinar la dulicación 5 6incular is*t5 a la de#inición de si!e: boolean is*t54 _`Ob return 0 XX si!e4 _`Od La creación de un sistea liio re@uiere la eliinación de dulicados, aun@ue sean unas cuantas líneas de código. í8ese en el siguiente e8elo: ublic 6oid scaleTo
image* scaling$actor* scaling$actorT
_`Od ublic s5nc%roni!ed 6oid rotate int degrees4 _`Ob replaceImageRImage8tilities.get4otatedImageRimage* degreesT
_`Od pri+ate +oid replaceImageR4enderedOp newImage R
image.disposeRT S-stem.gcRT image Q newImageT ]^=d
(l e>traer a este reducido ni6el, coen!aos a detectar inculiientos de R/. /or ello, odríaos cabiar un nue6o étodo e>traído a otra clase. *sto auenta su 6isibilidad. traer el nue6o étodo 5 usarlo en otro conte>to di#erente. *sta reutili!ación ínia uede reducir considerableente la cole8idad del sistea. aber cóo lograrlo es #undaental ara alcan!ar la reutili!ación a gran escala. *l atrón &7todo de plantillaOWU es una técnica u5 utili!ada ara eliinar dulicados de ni6el suerior. /or e8elo: ublic class acation/olic5 _`Ob ublic 6oid accrue-i6isionacation4 _`Ob QQ código ara calcular las 6acaciones en #unción de las %oras traba8adas QQY QQ código ara garanti!ar @ue las 6acaciones culen los ínios legales QQY QQ código ara alicar 6acation al registro a5roll QQY _`Od ublic 6oid accrue*-i6isionacation4 _`Ob QQ código ara calcular las 6acaciones en #unción de las %oras traba8adas QQY QQ código ara garanti!ar @ue las 6acaciones culen los ínios legales QQ Y QQ código ara alicar 6acation al registro a5roll QQY _`Od _`Od *l código entre accrue-i6isionacation 5 accrue*uroean-i6isionacation es r=cticaente idéntico, a e>ceción del c=lculo de ínios legales. *sa arte del de l algorito cabia en #unción del tio de eleado. /odeos eliinar la dulicación e6idente si alicaos el atrón de &7todo de plantilla: abstract ublic class acation/olic5 _`Ob ublic 6oid accrueacation4 _`Ob calculate(aseKacation"oursRT alter$or!egalMinimumsRT appl-3oPa-rollRT _`Od ri6ate 6oid calculate)aseacationours4 _`Ob Q Y Q _`Od abstract rotected 6oid alterorLegalMinius4 ri6ate 6oid al5To/a5roll4 _`Ob Q Y Q _`Od
_`Od ublic class acation/olic5 e>tends acation/olic5 _`Ob [<6erride rotected 6oid alterorLegalMinius4 _`Ob QQ Lógica eseci#ica de **.. _`Od _`Od ublic class *acation/olic5 e>tends acation/olic5 _`Ob [<6erride rotected 6oid alterorLegalMinius4 _`Ob QQ Lógica eseci#ica de la *. _`Od _`Od Las subclases ocuan el 6acío generado en el algorito accrueacation 5 solaente roorcionan los datos @ue no est=n es t=n dulicados.
#Epresi+idad Muc%os teneos e>eriencia con código enre6esado. Muc%os lo %eos creado. *s #=cil crear código @ue entendaos, 5a @ue durante su creación nos centraos en corender el roblea @ue intentaos resol6er. Los encargados de antener el código no lo corender=n de la isa #ora. *l rincial coste de un ro5ecto de software es su anteniiento a largo la!o. /ara inii!ar los osibles de#ectos al reali!ar cabios, es #undaental @ue corendaos el #uncionaiento del sistea. (l auentar la cole8idad de los sisteas, el rograador necesita =s tieo ara entenderlo 5 auentan las osibilidades de errores. /or tanto, el código debe e>resar con claridad la intención de su autor. Cuando =s claro sea el código, enos tieo erder=n otros en intentar corenderlo. *sto reduce los de#ectos 5 el coste de anteniiento. /uede e>resarse si elige nobres adecuados. *l ob8eti6o es 6er el nobre de una clase 5 #unción, 5 @ue sus resonsabilidades no nos sorrendan. Tabién uede e>resarse si reduce el taa3o de #unciones 5 clases. (l %acerlo, resulta =s sencillo asignarles nobres, crearlas 5 corenderlas. resarse es usar una noenclatura est=ndar. Los atrones de dise3o, or e8elo, se basan en la counicación 5 en la caacidad de e>resión. (l usar los nobres de atrones atron es est=ndar, coo Cresi6as. no de los rinciales ob8eti6os de una rueba es ser6ir de docuentación ediante e8elos. Los @ue lean las ruebas deben entender con c on #acilidad ara @ué sir6e una clase. /ero la #ora =s iortante de ser e>resi6o es la r=ctica. ( enudo, conseguios @ue el código #uncione 5 asaos al siguiente roblea sin deteneos en #acilitar la lectura del código ara otros. Bo ol6ide @ue seguraente sea el ró>io @ue lea el código. /or tanto, a#ronte su creación con orgullo. -edi@ue tieo a sus #unciones 5 clases. eleccione nobres e8ores, di6ida las #unciones e>tensas en otras =s reducidas 5 cuide su obra. *l cuidado es un recurso recioso.
Clases - mDtodos m:nimos "ncluso concetos tan b=sicos coo la eliinación de código dulicado, la e>resi6idad del código 5 R/ ueden e>agerarse. *n un es#uer!o or reducir el taa3o de clases 5 étodos, odeos crear deasiadas clases 5 étodos reducidos. *sta regla tabién sugiere inii!ar la cantidad de #unciones 5 clases. na gran cantidad de clases 5 étodos suele indicar un dogatiso sin sentido. "agine un est=ndar de código @ue insista en la creación de una inter#a! ara todas las clases, o a rograadores @ue insisten en @ué caos 5 coortaientos siere deben seararse en clases de datos 5 clases de coortaiento. *ste doga debe e6itarse 5 cabiarse or un en#o@ue =s rag=tico. Buestro ob8eti6o es reducir el taa3o general del sistea ade=s del taa3o de clases 5 #unciones, ero recuerde @ue esta regla es la de enor rioridad de las cuatro. /or ello, aun@ue sea iortante reducir la cantidad de clases 5 #unciones, es =s iortante contar con ruebas, eliinar dulicados 5 e>resarse correctaente.
Conclusión H*>isten r=cticas sencillas @ue uedan reela!ar a la e>erienciaI /or suuesto @ue no. in ebargo, las r=cticas descritas en este caítulo 5 en el libro son una #ora cristali!ada de décadas de e>eriencia de uc%os autores. La r=ctica del dise3o correcto ania 5 erite a los rograadores adotar rinciios 5 atrones @ue en caso contrario tardarían a3os en arender.
(ibliograf:a ;7P#>: )9treme Programming )9plained: )mbrace Change, $ent )ec&, (ddison 7esle5, 999. ;O$>: Design Patterns: )lements of e%sable b0ect riented Software Software, Gaa et al., (ddison17esle5, 99N.
G Concurrencia or )rett L. c%uc%ert
L'os ob0etos son abstracciones de procesamiento" 'os s%bprocesos son abstracciones de programacionesM"
\James O. Coplien;=> La creación de rograas concurrentes liios es colicada, u5 colicada. *s uc%o =s sencillo crear código @ue se e8ecute en un iso roceso. Tabién es #=cil crear código de subrocesaiento ;ltile @ue are!ca correcto en la suer#icie ero @ue esté da3ado a ni6eles =s ro#undos. *ste código #unciona correctaente %asta @ue el sistea se soete a deterinadas resiones. *n este caítulo anali!areos la necesidad de la rograación concurrente 5 sus
di#icultades. Tras ello, resentareos di6ersas recoendaciones ara suerar dic%as di#icultades 5 crear código concurrente liio. /or ;ltio, #inali!areos con los robleas relacionados con la rueba de código concurrente. La concurrencia liia es un tea cole8o, erecedor de un libro roio. (@uí, intentareos o#recer una 6isión general, @ue desués aliareos en el aéndice (. i sileente tiene curiosidad or el tea, le bastar= con este caítulo. i necesita entender la concurrencia a un ni6el =s ro#undo, consulte tabién el aéndice.
&Por 9uD concurrencia' La concurrencia es una estrategia de des6inculación. Bos erite des6incular lo @ue se %ace de dónde se %ace. *n alicación de un solo roceso, el @ué 5 el cu=ndo est=n tan #ireente 6inculados @ue el estado de la alicación se uede deterinar anali!ando la %uella de la ila. n rograador @ue deure este tio de sisteas uede de#inir un unto de interrución o 6arios4 5 saber el estado de la alicación en #unción del unto al @ue se llegue. La des6inculación del @ué del dónde uede e8orar considerableente el rendiiento 5 la estructura de una alicación. -esde un unto de 6ista estructural, la alicación arece una serie de e@uios colaboradores 5 no un gran bucle rincial. *sto uede %acer @ue el sistea sea =s #=cil # =cil de corender 5 o#rece di6ersas #oras de searar las reocuaciones. /ongaos or caso el odelo er6let est=ndar de alicaciones 7eb. *stos sisteas se e8ecutan ba8o un contenedor 7eb o *J) @ue gestiona arcialente la concurrencia. Los ser6let se e8ecutan de #ora asíncrona cuando se reciben solicitudes 7eb. *l rograador de los ser6let no tiene @ue gestionar todas las solicitudes entrantes. *n rinciio, la e8ecución de cada ser6let 6i6e en un undo roio 5 se des6incula del resto. *6identeente, si #uera tan sencillo, no necesitaríaos este caítulo. -e %ec%o, la des6inculación roorcionada or los contenedores 7eb dista uc%o de ser er#ecta. Los rograadores de ser6let ser 6let deben asegurarse de @ue sus rograas sean correctos. Bo obstante, las 6enta8as estructurales del odelo de ser6let son signi#icati6as. /ero la estructura no es el ;nico oti6o ara adotar la concurrencia. (lgunos sisteas tienen liitaciones de tieo de resuesta 5 roducción @ue re@uieren soluciones concurrentes anuales. "agine un disositi6o ara a3adir in#oración, con un solo roceso, @ue obtiene datos de distintos sitios 7eb 5 los cobina en un resuen diario. (l tener un solo roceso, accede or tuos a cada sitio 7eb 5 siere terina uno antes de coen!ar el siguiente. u recorrido diario debe e8ecutarse en enos de 2V %oras. in ebargo, al a3adir nue6os sitios 7eb, el tieo auenta %asta necesitarse =s de 2V %oras ara recoilar todos los datos. *l ;nico roceso roc eso ilica una rolongada esera ara coletar la *Q. /odríaos e8orar el rendiiento con a5uda de un algorito de subrocesaiento ;ltile @ue 6isite =s de un sitio 7eb or 6e!. "agine un sistea @ue rocesa un usuario or 6e! 5 sólo re@uiere un segundo or cada uno. u caacidad de resuesta es 6=lida ara un n;ero reducido de usuarios ero si auenta, tabién lo %ace el tieo de resuesta del sistea. Bing;n usuario @uerr= eserar a otros 0. /odríaos e8orar el tieo de resuesta de este sistea rocesando 6arios usuarios a la 6e!. "agine un sistea @ue interrete grandes con8untos de datos ero @ue sólo o#re!ca una solución coleta tras rocesarlos todos. e odría rocesar cada con8unto
de datos en un e@uio distinto, ara oder rocesarlos todos en aralelo.
Mitos e imprecisiones Tabién e>isten oti6os e6identes ara adotar la concurrencia aun@ue, coo indicaos antes, sea colicada. i no resta la su#iciente atención, ueden darse casos desagradables. eaos los itos e irecisiones =s %abituales: 'a conc%rrencia siempre me0ora el rendimiento: *n ocasiones lo %ace ero sólo cuando se uede coartir tieo entre 6arios rocesos o rocesadores. Binguna situación es tri6ial. )l diseo no cambia al crear programas conc%rrentes: -e %ec%o, el dise3o de un algorito concurrente uede ser u5 distinto al de un sistea de un solo roceso. La des6inculación entre el @ué 5 el cu=ndo suele tener un e#ecto iortante en la estructura del sistea. /o es importante entender los problemas de conc%rrencia al traba0ar con %n contenedor eb o )J=: *n realidad, debe saber lo @ue %ace su contenedor 5 rotegerlo de
robleas de actuali!aciones concurrentes concurren tes 5 blo@ueo, coo 6ereos desués. eaos otros asectos relacionados con la creación de software concurrente: 'a conc%rrencia genera cierta sobrecarga, tanto en rendiiento coo en la creación de código adicional. 'a conc%rrencia correcta es comple0a, incluso ara robleas sencillos. 'os errores de conc%rrencia no se s%elen repetir , de odo @ue se ignoranOU en lugar de considerarse 6erdaderos robleas. 'a conc%rrencia s%ele acarrear %n cambio f%ndamental de la estrategia de diseo.
2esaf:os HKué %ace @ue la rograación concurrente sea tan colicadaI í8ese en la siguiente clase: ublic class + _`Ob ri6ate int last"dsed ublic int getBe>t"d4 _`Ob return ZZlast"dsed _`Od _`Od "agine @ue creaos una instancia +, estableceos el cao last"dsed en V2 5 desués coartios la instancia entre dos rocesos. "agine a%ora @ue esos dos rocesos in6ocan el étodo getBe>t"d4 %a5 tres resultados osibles: *l rier roceso obtiene el 6alor VW, el segundo el 6alor VV 5 last"dsed es VV. *l rier roceso obtiene el 6alor VV, el segundo el 6alor VW 5 last"dsed es VV. *l rier roceso obtiene el 6alor VW, el segundo el 6alor VW 5 last"dsed es VW. *l sorrendente tercer resultadoONU se roduce cuando los dos rocesos coinciden. e debe a @ue ueden adotar 6arias rutas osibles en una línea de código de Ja6a 5 algunas generan resultados incorrectos. HCu=ntas rutas distintas e>istenI /ara resonder, debeos entender lo @ue %ace el coilador 8usto a tieo con el código de b.tes generado, 5 lo @ue el odelo de eoria de Ja6a considera atóico.
na r=ida resuesta, con el código de b.tes generado, es @ue e>isten 2 AO0 rutas de e8ecución di#erentesOOU ara los dos rocesos e8ecutados en el étodo getBe>t"d. i el tio de last"dsed cabia de int a long, el n;ero de rutas asciende a 2 O0V N. *6identeente, uc%as generan resultados 6=lidos. *l roblea es @ue alg%nas no lo hacen.
Principios de defensa de la concurrencia ( continuación le ostraos una serie de rinciios 5 técnicas ara roteger a sus sisteas de los robleas del código concurrente.
Principio de responsabilidad nica RS4P R/OAU establece @ue un étodo, clase o coonente sólo debe tener un oti6o ara cabiar. *l dise3o de concurrencia concurren cia es lo bastante cole8o coo ara ser un oti6o de cabio con derec%o roio 5, or tanto, debe seararse del resto del código. -esa#ortunadaente, es %abitual incrustar los detalles de la ileentación de concurrencia directaente en otro código de roducción. Tenga en cuenta los siguientes asectos: )l c2digo relacionado con la conc%rrencia tiene s% propio ciclo de desarrollo, cabios 5 a8ustes. )l c2digo relacionado con la conc%rrencia tiene s%s propios desaf+os, di#erentes 5 =s colicados, @ue los del código no relacionado con la concurrencia. *l n;ero de #oras en las @ue el código incorrecto basado en la concurrencia uede #allar lo colica 5a de or sí, sin la carga a3adida del código de alicación circundante. 4ecomendación: Separe el c2digo de conc%rrencia del resto del c2digoO9U.
CorolarioH !imitar el ámbito de los datos Coo %eos 6isto, dos rocesos @ue odi#ican el iso cao u ob8eto coartido ueden inter#erir entre ellos 5 ro6ocar un coortaiento ineserado. na solución consiste en usar la alabra cla6e s5nc%roni!ed ara roteger una sección iortante del código @ue use el ob8eto coartido, aun@ue con6iene liitar la cantidad de estas secciones. Cuantos =s untos actualicen datos coartidos, es =s robable @ue: e ol6ide de roteger uno o 6arios de esos untos, 5 se da3e el código @ue odi#ica los datos coartidos. e duli@ue el es#uer!o necesario ara garanti!ar la rotección de todos los eleentos inculiiento de -REA0U4. Resulta colicado deterinar el origen de los #allos, @ue or naturale!a son di#íciles de detectar. 4ecomendación: )ncaps%le los datos . limite el acceso a los datos compartidos.
CorolarioH 8sar copias de datos na #ora de e6itar datos coartidos es no coartirlos. *n algunos casos se ueden coiar ob8etos 5 rocesarlos rocesar los coo si #ueran de sólo lectura. *n otros, se s e ueden coiar ob8etos, recoilar los resultados de 6arios rocesos en las coias 5 desués cobinar los resultados en un iso roceso. i e>iste una #ora sencilla de e6itar los ob8etos coartidos, el código resultante tendr= enos robleas. /uede @ue le reocue el coste de la creación de ob8etos adicionales. Merece la ena e>erientar 5 corobar si es un roblea real. Bo obstante, si el uso de coias de ob8etos erite al código e6itar la sincroni!ación, las 6enta8as de e6itar el blo@ue coensan la creación adicional 5 la sobrecarga de la recolección de eleentos sin usar.
CorolarioH !os procesos deben ser independientes /ruebe a crear el código de sus rocesos de #ora @ue cada uno sea indeendiente 5 no coarta datos con otros. Cada uno rocesa una solicitud cliente 5 todos los datos necesarios ro6ienen de un origen sin coartir 5 se alacenan coo 6ariables locales. -e este odo, los rocesos se coortan coo si #ueran los ;nicos del undo 5 no e>istieran re@uisitos de sincroni!ación. /or e8elo, las subclases de tter6let reciben toda su in#oración coo ar=etros asados en los étodos doGet 5 do/ost. *sto %ace @ue cada ser6let act;e coo si disusiera de su roio e@uio. Mientras el código del ser6let sólo use 6ariables locales, es iosible @ue cause robleas de sincroni!ación. *6identeente, uc%as alicaciones @ue usan ser6let se toan con recursos coartidos coo cone>iones de base de datos. 4ecomendación: 3ntente dividir los datos en s%bcon0%ntos independientes *%e se p%edan procesar en procesos independientes, posiblemente en distintos procesadores.
Conocer las bibliotecas Ja6a o#rece uc%as e8oras ara el desarrollo concurrente con resecto a 6ersiones anteriores. *>isten di6ersos asectos @ue tener en cuenta a la %ora de crear código de rocesos en Ja6a : sar las colecciones coatibles con rocesos roorcionadas. sar la estructura de e8ecución de tareas no relacionadas. sar soluciones antiblo@ueo siere @ue sea osible. arias clases de bibliotecas no son coatibles con rocesos.
Colecciones compatibles con procesos *n los albores de Ja6a, -oug Lea escribió el conocido libroAU Conc%rrent Programming in Java. (l iso tieo, desarrolló 6arias colecciones coatibles con rocesos, @ue osteriorente asaron as aron a #orar arte del J-$ en el a@uete 8a6a.util.concurrent. Las colecciones de dic%o a@uete a@u ete son coatibles con casos de rocesos ;ltiles 5 tienen un rendiiento adecuado. -e %ec%o, %ec% o, la ileentación
Concurrentas%Ma tiene e8or rendiiento @ue as%Ma en la a5oría de los casos. Tabién erite lecturas 5 escrituras siult=neas, 5 disone de étodos @ue aditen oeraciones de coosición %abituales @ue en caso contrario serian incoatibles con subrocesos. i Ja6a es su entorno de desarrollo, coience con Concurrentas%Ma. *>isten otras clases a3adidas ara aditir dise3o a6an!ado de concurrencia. eaos algunos e8elos: ReentrantLoc& )lo@ueo @ue se uede ad@uirir en un étodo 5 liberar en otro. sea%ore na ileentación del cl=sico se=#oro, un blo@ueo con un contador. Count-o?nLatc% )lo@ueo @ue esera un n;ero de e6entos antes de liberar todos los subrocesos retenidos. -e este odo todos tienen la isa oortunidad de iniciarse al iso tieo. 4ecomendación: evise las clases de las *%e disponga" )n el caso de Java, debe familiari(arse con 0ava"%til"conc%rrent, 0ava"%til"conc%rrent"atomic 0ava"%til"conc%rrent"atomic . 0ava"%til"conc%rrent"locks.
Conocer los modelos de e)ecución *>isten di6ersas #oras de di6idir el coortaiento de una alicación concurrente. /ara describirlos debe conocer ciertas de#iniciones b=sicas. Recursos 6inculados Recursos de taa3o o n;ero #i8o usados en un entorno concurrente, coo or e8elo cone>iones de base de datos 5 b;#er de lecturaQescritura de taa3o #i8o. *>clusión utua ólo un roceso uede acceder a datos o a un recurso coartido or 6e!. "nanición e iide @ue un roceso o gruo de rocesos contin;en deasiado tieo o inde#inidaente. /or e8elo, si erite riero la e8ecución de los rocesos =s r=idos, los @ue se e8ecutan durante =s tieo ueden erecer de inanición si los rieros no terinan nunca. )lo@ueo -os o =s rocesos eseran a @ue abos terinen. Cada roceso tiene un recurso 5 ninguno uede terinar %asta @ue obtenga el otro recurso. )lo@ueo acti6o /rocesos blo@ueados, intentando reali!ar su labor ero estorb=ndose unos a otros. /or oti6os de resonancia, los rocesos siguen intentando a6an!ar ero no ueden durante deasiado tieo, o de #ora inde#inida. Tras ostrar estas de#iniciones, 5a odeos describir los distintos odelos de e8ecución eleados en la rograación concurrente.
ProductorFConsumidor;N> no o 6arios rocesos roductores crean traba8o 5 lo a3aden a un b;#er o a una cola. no o 6arios rocesos consuidores ad@uieren dic%o traba8o de la cola 5 lo coletan. La cola entre roductores 5 consuidores es un recurso 6inculado, lo @ue signi#ica @ue los roductores deben eserar eser ar a @ue se libere esacio en la cola antes de d e escribir 5 los consuidores deben eserar %asta @ue %a5a algo @ue consuir en la cola. La coordinación entre roductores 5 consuidores a tra6és de la cola %ace @ue unos eitan se3ales a otros. Los roductores escriben en la cola e indican @ue 5a no est= 6acía. Los consuidores leen de la cola e indican @ue 5a no est= llena. (bos eseran la noti#icación ara oder continuar.
!ectoresF#scritores ;NG> Cuando un recurso coartido act;a b=sicaente coo #uente de in#oración ara lectores ero ocasionalente se actuali!a or arte de escritores, la roducción es un roblea. *l én#asis de la roducción uede ro6ocar la inanición 5 la acuulación de in#oración caducada. Las actuali!aciones ueden a#ectar a la roducción. La coordinación de lectores ara @ue no lean algo @ue un escritor est= actuali!ando 5 6ice6ersa es colicada. Los escritores tienden a blo@uear a los lectores durante eriodos rolongados, lo @ue genera robleas de roducción. *l desa#ío consiste en e@uilibrar las necesidades de abos ara satis#acer un #uncionaiento correcto, roorcionar una roducción ra!onable 5 e6itar la inanición. na sencilla estrategia %ace @ue los escritores eseren %asta @ue de8e de %aber lectores antes de reali!ar una actuali!ación. i %a5 lectores continuos, los escritores erecen de inanición. /or otra arte, si %a5 escritores #recuentes 5 se les asigna rioridad, la roducción se 6e a#ectada. -eterinar el e@uilibrio 5 e6itar robleas de actuali!ación concurrente es el ob8eti6o de este odelo.
!a cena de los filósofos ;N> "agine 6arios #ilóso#os sentados alrededor de una esa redonda. ( la i!@uierda de cada uno %a5 un tenedor. *n el centro de la esa, una gran #uente de esaguetis. Los #ilóso#os asan el tieo ensando a enos @ue tengan %abre. Cuando tienen %abre, utili!an los tenedores situados a abos lados ara coer. Bo ueden coer a enos @ue tengan dos tenedores. i el #ilóso#o situado a la derec%a o i!@uierda de otros 5a tiene uno de los tenedores @ue necesita, tendr= @ue eserar a @ue terine de coer 5 de8e los tenedores. Cuando un #ilóso#o terina de coer, 6uel6e a colocar los tenedores en la esa %asta @ue 6uel6e a tener %abre. Cabie los #ilóso#os or rocesos 5 los tenedores or recursos 5 tendr= un roblea %abitual en uc%as alicaciones en las @ue los rocesos coiten or recursos. ( enos @ue se dise3en correctaente, los sisteas @ue coiten de esta #ora e>erientan robleas de blo@ueo, blo@ueo utuo, roducción 5 degradación de la e#icacia. La a5oría de robleas de concurrencia @ue encontrar= ser=n alguna 6ariante de éstos. (nalice los algoritos 5 cree soluciones roias ara estar rearado cuando sur8an robleas de concurrencia. 4ecomendación: Aprenda estos algoritmos b#sicos . comprenda s%s sol%ciones.
2ependencias entre mDtodos sincronizados Las deendencias entre étodos sincroni!ados generan sutiles errores en el código concurrente. Ja6a cuenta con s5nc%roni!ed, @ue rotege étodos indi6iduales. Bo obstante, si %a5 =s de un étodo sincroni!ado en la isa clase coartida, uede @ue su sistea sea incorrectoAU. 4ecomendación: )vite %sar m#s de %n m7todo en %n ob0eto compartido. *n ocasiones tendr= @ue usar =s de un étodo en un ob8eto coartido. *n ese caso, %a5 tres #oras de crear código correcto:
(lo9ueo basado en clientes: *l cliente debe blo@uear al ser6idor antes de in6ocar el rier étodo 5 asegurarse de @ue el alcance del blo@ue inclu5e el código @ue in6o@ue el ;ltio étodo. (lo9ueo basado en ser+idores: -ebe crear un étodo en el ser6idor @ue blo@uee el ser6idor, in6o@ue todos los étodos 5 desués anule el blo@ueo. *l cliente debe in6ocar el nue6o étodo. Ser+idor adaptado: Cree un interediario @ue realice el blo@ue. *s un e8elo de blo@ueo basado en ser6idores en el @ue el ser6idor original no se uede odi#icar.
4educir el tama%o de las secciones sincronizadas La alabra cla6e s5nc%roni!ed resenta un blo@ueo. Todas las secciones de código rotegidas or el iso blo@ue sólo tendr=n un roceso r oceso @ue las e8ecute en un oento dado. Los blo@ueos son costosos 5a @ue generan retrasos 5 a3aden sobrecarga. /or ello, no con6iene colasar el código con instrucciones s5nc%roni!ed. /or otra arte, las secciones críticasANU deben rotegerse, de odo @ue debeos dise3ar nuestro código con el enor n;ero osible de secciones críticas. (lgunos rograadores intentan lograrlo aliando el taa3o de sus secciones críticas. in ebargo, al aliar la sincroni!ación =s all= de la sección crítica ínia auentan los robleas 5 a#ecta negati6aente al rendiientoAOU. 4ecomendación: ed%(ca al m#9imo el tamao de las secciones s.nchroni(ed secciones s.nchroni(ed .
Crear código de cierre correcto es complicado Crear un sistea acti6o 5 @ue se e8ecute inde#inidaente es distinto a crear algo @ue #uncione de #ora teoral 5 desués se cierre correctaente. *ntre los robleas =s %abituales destacan los blo@ueosAAU, con rocesos @ue eseran una se3al ara continuar @ue nunca se roduce. "agine, or e8elo, un sistea con un roceso rincial @ue genera 6arios rocesos secundarios 5 @ue @ ue esera a @ue todos terinen antes de liberar sus recursos 5 cerrarse. HKué sucede si uno de los rocesos secundarios est= blo@ueadoI *l rincial eserar= inde#inidaente 5 el sistea nunca se cerrar=. "agine a%ora un sistea siilar al @ue se le indica @ue se cierre. *l roceso rincial indica a todos los secundarios @ue abandonen aband onen sus tareas 5 terinen. /ero iagine @ue dos rocesos secundarios #uncionan coo ar roductorQconsuidor 5 @ue el roductor recibe una se3al del rincial 5 se cierra r=idaente. *l consuidor esera un ensa8e del roductor 5 uede @uedar blo@ueado blo@ue ado en un estado en el @ue no recibe la se3al del rincial, lo @ue tabién iide @ue éste #inalice. on situaciones %abituales. /or tanto, si tiene @ue crear código concurrente con cierres correctos, tendr= @ue dedicar tieo a @ue el cierre se rodu!ca de #ora correcta. 4ecomendación: Planifi*%e con antelaci2n el proceso de cierre . pr%7belo hasta *%e f%ncione" 'e llevar# m#s tiempo del *%e espera" epase los algoritmos e9istentes por*%e ser# complicado.
Probar código con procesos -eostrar @ue el código es correcto no resulta r=ctico. Las ruebas no garanti!an su corrección. in ebargo, las ruebas adecuadas ueden inii!ar los riesgos, en esecial en alicaciones de un solo roceso. Cuando %a5 dos o =s rocesos @ue usan el iso código 5 traba8an con datos coartidos, la situación se 6uel6e =s cole8a. 4ecomendación: Cree pr%ebas *%e p%edan detectar problemas . e0ec8telas peri2dicamente, con distintas config%raciones de programaci2n . del sistema, . cargas" Si las pr%ebas fallan, identifi*%e el fallo" /o lo ignore por*%e las pr%ebas s%peren %na e0ec%ci2n posterior .
a5 uc%os #actores @ue tener en cuenta. eaos algunas recoendaciones concretas: Considere los #allos coo osibles robleas de los rocesos. Consiga @ue riero #uncione el código sin rocesos. *l código con rocesos se debe oder conectar a otros eleentos. *l código con rocesos debe ser odi#icable. *8ecute con =s rocesos @ue rocesadores. *8ecute en di#erentes lata#oras. -ise3e el código ara robar 5 #or!ar #allos
Considerar los fallos como posibles problemas de los procesos *l código con rocesos %ace @ue #allen eleentos @ue no deberían #allar. Muc%os desarrolladores desconocen cóo interact;an los rocesos con otro tio de código. Los robleas del código con rocesos ueden ostrar sus síntoas una 6e! cada il o un illón de e8ecuciones. Los intentos or reetir los sisteas ueden resultar #rustrantes, lo @ue suele ro6ocar @ue los rograadores rogra adores consideren el #allo coo algo aislado. *s recoendable r ecoendable asuir @ue los #allos aislados no e>isten. Cuanto =s los ignore, a5or ser= la cantidad de código @ue se acuule sobre un en#o@ue de#ectuoso. 4ecomendación: /o ignore los fallos del sistema como algo aislado.
Conseguir 9ue primero funcione el código sin procesos /uede arecer e6idente ero no est= de =s recordarlo. (seg;rese de @ue el código #unciona #uera de sus rocesos. /or lo general, esto signi#ica crear algunos /
#l código con procesos se debe poder conectar a otros elementos Cree el código coatible con la concurrencia de #ora @ue se ueda e8ecutar en distintas con#iguraciones: n roceso, 6arios rocesos 5 6ariarlo durante la e8ecución. *l código con rocesos interact;a con algo @ue uede ser real o robado. *8ecutar con ruebas dobles e8ecutadas de #ora r=ida, lenta 5 6ariable. Con#igurar ruebas @ue e8ecutar en di#erentes iteraciones. 4ecomendación: )l c2digo con procesos debe poder conectar a otros elementos . e0ec%tar en distintas config%raciones.
#l código con procesos debe ser modificable La obtención del e@uilibrio adecuado de rocesos suele re@uerir oeraciones de ensa5o 5 error. *n las #ases iniciales, coruebe el rendiiento del sistea ba8o di#erentes con#iguraciones. /erita @ue se uedan odi#icar los distintos rocesos 5 tabién durante la e8ecución del sistea. Tabién uede eritir la odi#icación auto=tica en #unción de la roducción 5 la utili!ación del sistea.
#)ecutar con más procesos 9ue procesadores Cuando el sistea cabia de tarea, se roducen reacciones. /ara roo6er el intercabio de tareas, realice la e8ecución con =s rocesos @ue rocesadores o n;cleos. Cuanto a5or sea la #recuencia de intercabio de las tareas, =s robabilidades e>isten de @ue el código care!ca de una sección crítica o se rodu!can blo@ueos.
#)ecutar en diferentes plataformas *n 200O dise3aos un curso sobre rograación concurrente, rincialente en < +. La clase se resentó con 7indo?s +/ e8ecutado en una M. e crearon ruebas ara ilustrar condiciones de #allo @ue #allaban #a llaban con =s #recuencia en < + @ue en +/. *n todos los casos, el código robado era incorrecto. *sto re#uer!a el %ec%o de @ue cada sistea oerati6o tiene una olítica de rocesos di#erente @ue a#ecta a la e8ecución del código. *l código con rocesos ;ltiles se coorta de #ora distinta en cada entornoA9U. -ebe e8ecutar sus ruebas en todos los entornos de ileentación osibles. 4ecomendación: )0ec%te el c2digo con procesos en todas las plataformas de destino con frec%encia . en las fases iniciales.
2ise%ar el código para probar - forzar fallos *s %abitual @ue los #allos del código concurrente se oculten. Las ruebas sencillas no suelen ostrarlos. *n realidad, suelen ocultarse durante el rocesaiento noral. /ueden aarecer %oras, días o seanas desués.
La ra!ón de @ue los robleas de rocesos sean in#recuentes, esor=dicos 5 aenas se reitan es @ue sólo #allas algunas de las iles de rutas osibles @ue recorren una sección 6ulnerable. /or tanto, la robabilidad de adotar una ruta #allida es realente ba8a, lo @ue di#iculta la detección 5 la deuración. e reguntar= cóo auentar las osibilidades de caturar estos casos. /uede dise3ar el código 5 #or!arle a @ue se e8ecute en di#erentes órdenes a3adiendo étodos coo
Manual /uede a3adir in6ocaciones de ?ait4, slee4, 5ield4 5 riorit54 anualente a su código, en esecial si tiene @ue robar un #ragento esecialente escabroso. eaos un e8elo: ublic s5nc%roni!ed tring ne>trlt44 _`Ob tring url X urlGenerator.ne>t4 T%read.5ield4 QQ se a3ade ara ruebas. udateasBe>t4 return url _`Od return null _`Od La in6ocación de 5ield4 cabia la ruta de e8ecución adotada or el código 5 osibleente %ace @ue el código #alla donde no lo %acía antes. i el código #alla, no se debe a la in6ocación de 5ield4 a3adida90U. e debe a @ue el código es incorrecto 5 %eos %ec%o @ue el #allo sea =s e6idente. *ste en#o@ue resenta 6arios robleas: Tendr= @ue buscar anualente los untos adecuados donde %acerlo. HCóo sabe dónde incluir la in6ocación 5 @ué tio de in6ocación usarI La resencia de este código en un entorno de roducción ralenti!a innecesariaente el código. *s un en#o@ue @ue uede o no detectar los #allos de %ec%o, no las tiene todas consigo. Lo @ue necesitaos es una #ora de %acerlo durante la #ase de ruebas, no de roducción. Tabién debeos oder e!clar con#iguraciones entre e8ecuciones, lo @ue @ ue auenta las robabilidades de detectar los errores. *6identeente, si di6idios el sistea /
Automática /uede usar %erraientas coo la estructura orientada a asectos, CGL") o (M ara instruentar su código ediante rograación. rogr aación. /or e8elo, odría usar una clase con un ;nico étodo: ublic class T%readJiggle/oint _`Ob ublic static 6oid 8iggle4 _`Ob _`Od _`Od /uede a3adir in6ocaciones en distintos untos del código: ublic s5nc%roni!ed tring ne>trlt44 _`Ob T%readJiggle/oint.8iggle4 tring url X urlGenerator.ne>t4 T%readJiggle/oint.8iggle4 udateasBe>t4 T%readJiggle/oint.8iggle4 return url _`Od return null _`Od Tras ello, use un sencillo asecto @ue seleccione aleatoriaente entre no %acer nada, ausar o generar un resultado. r esultado. "agine @ue la clase T%readJiggle/oint tiene dos ileentaciones. La riera ileenta 8iggle ara no %acer nada 5 se usa en roducción. La segunda genera un n;ero aleatorio ara elegir entre slee, 5ield o nada. i e8ecuta sus ruebas il 6eces con 8iggle de #ora aleatoria, uede descubrir algunos alguno s #allos. i la rueba es satis#actoria, al enos uede #elicitarse or %aber actuado correctaente. (un@ue sea un tanto sile, uede resultar una oción ra!onable ra!onab le en lugar de recurrir a una %erraienta % erraienta =s so#isticada. 9U La %erraienta ConTest , desarrollada or ")M, tiene un #uncionaiento siilar ero es =s so#isticada. *l ob8eti6o es @ue los rocesos del código se e8ecuten en distinto orden en oentos di#erentes. La cobinación de ruebas bien escritas 5 e8ecuciones aleatorias uede auentar considerableente la caacidad caac idad de detectar errores. 4ecomendación: se estas estrategias para detectar errores.
Conclusión *s colicado conseguir código concurrente correcto. *l código sencillo se uede colicar al a3adir 6arios rocesos 5 datos coartidos. i tiene @ue crear código concurrente, tendr= @ue %acerlo con rigor o se en#rentar= a sutiles 5 esor=dicos #allos. *n rier lugar, siga el rinciio de resonsabilidad ;nica. -i6ida su sistea en 6arios /
Cono!ca los orígenes de los robleas de concurrencia: 6arios rocesos @ue oeren en datos coartidos o usen una agruación de recursos co;n. Los casos de líites, coo el cierre correcto o la conclusión de la iteración de un bucle, ueden ser esecialente esinosos. Cono!ca su biblioteca 5 los algoritos #undaentales. -ebe corender cóo las #unciones de la biblioteca eriten resol6er robleas siilares a los de los algoritos #undaentales. (renda a locali!ar regiones del código @ue se uedan blo@uear 5 blo@uéelas. Bo blo@uee otras regiones @ue no lo necesiten. neces iten. *6ite in6ocar una sección blo@ueada desde otra. /ara ello debe saber si un eleento est= coartido o no. Redu!ca la cantidad de ob8etos coartidos 5 su =bito. Cabie los dise3os de los ob8etos con datos coartidos ara acoodar clientes en lugar de obligar a los clientes a gestionar el estado coartido. Los robleas se acuular=n. Los @ue no aare!can inicialente suelen considerarse esor=dicos 5 suelen roducirse en la #ase de carga o de odo aarenteente aleatorio. /or tanto, debe oder e8ecutar su código con rocesos en di#erentes con#iguraciones 5 lata#oras de #ora reetida 5 continua. La caacidad de rueba, algo natural si alica las tres le5es de T--, ilica cierto ni6el de conecti6idad, lo @ue o#rece la coatibilidad necesaria ara e8ecutar código en distintas con#iguraciones. La robabilidad de detectar errores e8ora si se toa el tieo necesario ara instruentar su código. /uede %acerlo anualente o ediante tecnologías autoati!adas. =galo en las #ases iniciales. *s aconse8able e8ecutar el código basado en rocesos durante el a5or tieo osible antes de asarlo a roducción. i adota un en#o@ue liio, auentar=n las robabilidades de %acerlo de #ora correcta.
(ibliograf:a ;!ea@@>: Conc%rrent Programming in Java: Design Principles and Patterns, 2d. ed., -oug Lea, /rentice all, 999. ;PPP>: Agile Software Development: Principles, Patterns, and Practices, Robert C. Martin, /rentice all, 2002. ;P4A>: $he Pragmatic Programmer , (ndre? unt, -a6e T%oas, (ddison1 7esle5, 2000.
4efinamiento sucesi+o Caso r=ctico de un anali!ador de arguentos de línea de coandos
*ste caítulo es un caso r=ctico de re#inaiento sucesi6o. ereos un ódulo @ue coien!a correctaente ero no antiene dic%a corrección. Tras ello, 6ereos cóo se re#actori!a 5 se liia. Muc%os %eos tenido @ue anali!ar arguentos de línea de coando. i no disoneos de una utilidad ara ello, recorreos la atri! de cadenas asadas a la #unción rincial. /uede encontrar en contrar utilidades de calidad ero ninguna %ace e>actaente lo @ue necesitaos. /or ello, decidí crear una roia, a la @ue %e denoinado (rgs. (rgs es u5 #=cil de usar. )asta crearla con los arguentos de entrada 5 una cadena de #orato, 5 desués consultar a la instancia de (rgs los 6alores de los arguentos. í8ese en el siguiente e8elo: !istado F so de (rgs ublic static 6oid aintringU args4 _`Ob tr5 _`Ob (rgs arg X ne? (rgsl,k,d, args4
boolean logging X arg.get)ooleanmlh4 int ort X arg.get"ntmh4 tring director5 X arg.gettringmdh4 e>ecute(licationlogging, ort, director54 _`Od catc% (rgs*>cetion e4 _`Ob 5ste.out.rint#(rguent error: s_n, e.errorMessage44 _`Od _`Od Corobar= lo sencillo @ue es. Creaos una instancia de la clase (rgs con dos ar=etros. *l riero es la cadena de #orato # orato o es@uea: l, k, d. -e#ine tres arguentos de línea de coandos. *l riero, 1l, es un arguento booleano. *l segundo, 1, es un arguento entero. *l tercero, 1d, es un arguento de cadena. *l segundo ar=etro del constructor (rgs es la atri! de arguentos de línea de coandos asada a ain. i el constructor no genera (rgs*>cetion, la línea de coandos entrante se %a anali!ado 5 se uede consultar la instancia (rgs. e usan étodos coo get)oolean, get"nteger 5 gettring ara acceder a los 6alores de los arguentos or sus nobres. i %a5 un roblea, 5a sea en la cadena de #orato o en los arguentos de línea de coandos, se genera (rgs*>cetion. La descrición del error se uede recuerar del étodo errorMessage de la e>ceción.
Implementación de Args *l Listado V12 es la ileentación de la clase (rgs. *>aínela con atención. *l estilo 5 la estructura se %an traba8ado concien!udaente 5 esero @ue los iite. !istado .
(rgs.8a6a ac&age co.ob8ectentor.utilities.args iort static co.ob8ectentor.utilities.args.(rgs*>cetion.*rrorCode. iort 8a6a.util. ublic class (rgs _`Ob ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers ri6ate et]C%aracter^ argsound ri6ate List"terator]tring^ current(rguent ublic (rgstring sc%ea, tringU args4 t%ro?s (rgs*>cetion _`Ob ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 argsound X ne? as%et]C%aracter^4 arsec%easc%ea4 arse(rguenttrings(rra5s.asListargs44 _`Od ri6ate 6oid arsec%eatring sc%ea4 t%ro?s (rgs*>cetion _`Ob #or tring eleent : sc%ea.slit,44 i# eleent.lengt%4 ^ 04 arsec%ea*leenteleent.tri44 _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s (rgs*>cetion _`Ob
c%ar eleent"d 1 eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent "d4 i# eleentTail.lengt%4 XX 04 ars%alers.uteleent"d, ne? )oolean(rguentMars%aler44 else i# eleentTail.e@uals44 ars%alers.uteleent"d, ne? tring(rguentMars%aler44 else i# eleentTail.e@ualsk44 ars%alers.uteleent"d, ne? "nteger(rguentMars%aler44 else i# eleentTail.e@ualskk44 ars%alers.uteleent"d, ne? -ouble(rguentMars%aler44 else i# eleentTail.e@ualsU44 ars%alers.uteleent"d, ne? tring(rra5(rguentMars%aler44 else t%ro? ne? (rgs*>cetion"B(L"-(RGM*BTcetion _`Ob i# _`ObC%aracter.isLettereleent"d44 t%ro? ne? (rgs*>cetion"B(L"-(RGM*BTB(M*, eleent"d, null4 _`Od ri6ate 6oid arse(rguenttringsList]tring^ argsList4 t%ro?s (rgs*>cetion _`Ob #or current(rguent X argsList.list"terator4 current(rguent.%asBe>t44 _`Ob tring argtring X current(rguent.ne>t4 i# argtring.starts7it%144 _`Ob arse(rguentC%aractersargtring.substring44 _`Od else _`Ob current(rguent.re6ious4 brea& _`Od _`Od _`Od ri6ate 6oid arse(rguentC%aracterstring argC%ars4 t%ro?s (rgs*>cetion _`Ob #or int i X 0 i ] argC%ars.lengt%4 iZZ4 arse(rguentC%aracterargC%ars.c%ar(ti44 _`Od ri6ate 6oid arse(rguentC%aracterc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 _`Ob t%ro? ne? (rgs*>cetion B*+/*CT*-(RGM*BT, argC%ar, null4 _`Od else _`Ob argsound.addargC%ar4 tr5 _`Ob .setcurrent(rguent4 _`Od catc% (rgs*>cetion e4 _`Ob
e.set*rror(rguent"dargC%ar4 t%ro? e _`Od _`Od _`Od ublic boolean %asc%ar arg4 _`Ob return argsound.containsarg4 _`Od ublic int ne>t(rguent4 _`Ob return current(rguent.ne>t"nde>4 _`Od ublic boolean get)ooleanc%ar arg4 _`Ob return )oolean(rguentMars%aler.getaluears%alers.getarg4 )oolean(rguentMars%aler.getaluears%alers.getarg44 4 _`Od ublic tring gettringc%ar arg4 _`Ob return tring(rguentMars%aler.getaluears%alers.getarg4 tring(rguentMars%aler.getaluears%alers.getarg44 4 _`Od ublic int get"ntc%ar arg4 _`Ob return "nteger(rguentMars%aler.getalue ars%alers.getarg44 _`Od ublic double get-oublec%ar arg4 _`Ob return -ouble(rguentMars%aler.getaluears%alers.getarg -ouble(rguentMars%aler.getaluears%alers.getarg44 44 _`Od ublic tringU gettring(rra5c%ar arg4 _`Ob return tring(rra5(rguentMars%aler.getaluears%alers.ge tring(rra5(rguentMars%aler.getaluears%alers.getarg44 targ44 _`Od _`Od /uede leer el código de arriba a aba8o sin necesidad de saltar de un unto a otro ni buscar %acia adelante. Lo @ue seguraente segur aente bus@ue es la de#inición de (rguentMars%aler, @ue %eos oitido intencionadaente. Tras leer el código, corender= la inter#a! (rguentMars%aler 5 la #unción de sus 6ariantes. eaos algunas de ellas entre los listados V.W 5 V.N4. !istado FG
(rguentMars%aler.8a6a ublic inter#ace (rguentMars%aler _`Ob 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Od !istado F )oolean(rguentMars%aler.8a6a ublic class )oolean(rguentMars%aler ileents (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse ublic 6oid set "terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob booleanalue X true _`Od ublic static boolean getalue(rguentMars%aler a4 _`Ob
i# a X null '' a instanceo# )oolean(rguentMars%aler4 return )oolean(rguentMars%aler4 a4.booleanalue else return #alse _`Od _`Od !istado F tring(rguentMars%aler.8a6a iort static co.ob8ectentor.utilities.args.(rgs*>cetion.*rrorCode. ublic class tring(rguentMars%aler ileents (rguentMars%aler _`Ob ri6ate tring stringalue X ublic 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob stringalue X current(rguent.ne>t4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob t%ro? ne? (rgs*>cetionM""BGTR"BG4 _`Od _`Od ublic static tring getalue(rguentMars%aler a4 _`Ob i# a X null '' a instanceo# tring(rguentMars%aler4 return tring(rguentMars%aler4 a4.stringalue else return _`Od _`Od !istado FL "nteger(rguentMars%aler.8a6a iort static co.ob8ectentor.utilities.args.(rgs*>cetion.*rrorCode. ublic class "nteger(rguentMars%aler ileents (rguentMars%aler _`Ob ri6ate int intalue X 0 ublic 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob tring araeter X null tr5 _`Ob araeter X current(rguent.ne>t4 "ntalue X "nteger.arse"ntaraeter4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob t%ro? ne? (rgs*>cetionM""BG"BT*G*R4 _`Od catc% Buberorat*>cetion e4 _`Ob t%ro? ne? (rgs*>cetion"B(L"-"BT*G*R, araeter4 _`Od _`Od ublic static int getalue (rguentMars%aler a4 _`Ob i# a X null '' a instanceo# "nteger(rguentMars%aler4 return "nteger(rguentMars%aler4 a4.intalue else
return 0 _`Od _`Od Las otras 6ariantes de (rguentMars%aler sileente reiten este atrón en atrices double 5 tring 5 sólo colicarían el caítulo. /uede consultarlas coo e8ercicio. cetion 6éase el Listado V1O4. !istado F=
(rgs*>cetion.8a6a iort static co.ob8ectentor.utilities.args.(rgs*>cetion.*rrorCode. ublic class (rgs*>cetion e>tends *>cetion _`Ob ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X null ri6ate *rrorCode errorCode X <$ ublic (rgs*>cetion4 _`Ob_`Od ublic (rgs*>cetiontring essage4 _`Ob sueressage4 _`Od ublic (rgs*>cetion*rrorCode errorCode4 _`Ob t%is.errorCode X errorCode _`Od ublic (rgs*>cetion*rrorCode errorCode, tring error/araeter4 _`Ob t%is.errorCode X errorCode t%is.error/araeter X error/araeter _`Od ublic (rgs*>cetion*rrorCode errorCode, c%ar error(rguent"d, tring error/araeter4 _`Ob t%is.errorCode X errorCode t%is.error/araeter X error/araeter t%is.error(rguent"d X error(rguent"d _`Od ublic c%ar get*rror(rguent"d4 _`Ob return error(rguent"d _`Od ublic 6oid set*rror(rguent"dc%ar error(rguent"d4 _`Ob t%is.error(rguent"d X error(rguent"d _`Od ublic tring get*rror/araeter4 _`Ob return error/araeter _`Od ublic 6oid set*rror/araetertring error/araeter4 _`Ob t%is.error/araeter X error/araeter _`Od ublic *rrorCode get*rrorCode4 _`Ob return errorCode _`Od ublic 6oid set*rrorCode*rrorCode errorCode4 _`Ob t%is.errorCode X errorCode
_`Od ublic tring errorMessage4 _`Ob s?itc% errorCode4 _`Ob case <$: return T"LT: %ould not get %ere. case B*+/*CT*-(RGM*BT: return tring.#orat(rguent 1c une>ected., error(rguent"d4 case M""BGTR"BG: return tring.#oratCould not #ind string araeter #or 1c., error(rguent"d4 case "B(L"- "BT*G*R: return tring.#orat(rguent 1c e>ects an integer but ?as msh., error(rguent"d, error/araeter4 case M""BG"BT*G*R: return tring.#oratCould not #ind integer araeter #or 1c., error(rguent"d4 case "B(L"--<)L*: return tring.#orat(rguent 1c e>ects a double but ?as msh., error(rguent"d, error/araeter4 case M""BG-<)L*: return tring.#oratCould not #ind double araeter #or 1c., error(rguent"d4 case "B(L"-(RGM*BTB(M*: return tring.#oratmch is not a 6alid arguent nae., error(rguent"d4 case "B(L"-(RGM*BTeriencia coo rograador, artes del estilo o la estructura no le con6encer=n, ero esero @ue, desde un unto de 6ista global, considere @ue el rograa est= bien escrito 5 tiene una estructura liia. /or e8elo, debería ser e6idente cóo a3adir un nue6o tio de arguento, coo
una #ec%a o un n;ero cole8o, 5 @ue dic%a inclusión aenas re@ueriría código. *n de#initi6a, bastaría con una nue6a 6ariante de (rguentMars%aler, una nue6a #unción get+++ 5 una nue6a instrucción case en la #unción arsec%ea*leent. Tabién %abría un nue6o código (rgs*>cetion.*rrorCode 5 un nue6o ensa8e de error.
Cómo se /a realizado Bo dise3é este rograa de rinciio a #in en su #ora actual 5, sobre todo, no esero @ue ueda crear rograas liios 5 elegantes a la riera. i algo %eos arendido en las dos ;ltias décadas es @ue la rograación es un arte =s @ue una ciencia. /ara escribir código liio, riero debe crear código ier#ecto 5 desués liiarlo. Bo debería sorrenderle. Ea lo arendios en el colegio cuando los ro#esores noralente en 6ano4 nos obligaban a crear borradores de nuestras redacciones. *l roceso, nos decían, era escribir es cribir un rier borrador, desués desu és otro, 5 desués otros uc%os %asta lograr una 6ersión de#initi6a. /ara escribir redacciones liias, el re#inaiento debía ser continuado. Muc%os rograadores no6eles coo sucede con los alunos4 no siguen este conse8o. Creen @ue el ob8eti6o rincial es @ue el rograa #uncione. na 6e! @ue lo consiguen, asan a la siguiente tarea, 5 conser6an el estado #uncional del rograa, sea cual sea. Los rograadores e>erientados saben @ue esto es un suicidio ro#esional.
ArgsH #l primer borrador *l Listado V.A uestra una 6ersión inicial de la clase (rgs. unciona, ero es un desastre. !istado .N (rgs.8a6a rier borrador4 iort 8a6a.te>t./arse*>cetion iort 8a6a.util. ublic class (rgs _`Ob ri6ate tring sc%ea ri6ate tringU args ri6ate boolean 6alid X true ri6ate et]C%aracter^ une>ected(rguents X ne? Treeet]C%aracter^4 ri6ate Ma]C%aracter, )oolean^ boolean(rgs X ne? as%Ma]C%aracter, )oolean^4 ri6ate Ma]C%aracter, tring^ string(rgs X ne? as%MacC%aracter, tring^4 ri6ate Ma]C%aracter, "nteger^ int(rgs X ne? as%Ma]C%aracter, "nteger^4 ri6ate et]C%aracter^ argsound X ne? as%et]C%aracter^4 ri6ate int current(rguent ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X T"LT ri6ate *rrorCode errorCode X *rrorCode.<$
ri6ate enu *rrorCode _`Ob <$, M""BGTR"BG, M""BG"BT*G*R, "B(L"-"BT*G*R, B*+/*CT*-(RGM*BT_`Od ublic (rgstring sc%ea. tringU args4 t%ro?s /arse*>cetion _`Ob t%is.sc%ea X sc%ea t%is.args X args 6alid X arse4 _`Od ri6ate boolean arse4 t%ro?s /arse*>cetion _`Ob i# sc%ea.lengt%4 XX 0 '' args.lengt% XX 04 return true arsec%ea4 tr5 _`Ob arse(rguents4 _`Od catc% (rgs*>cetion e4 _`Ob _`Od return 6alid _`Od ri6ate boolean arsec%ea4 t%ro?s /arse*>cetion _`Ob #or tring eleent : sc%ea.slit,44 _`Ob i# eleent.lengt%4 ^ 04 _`Ob tring tried*leent X eleent.tri4 arsec%ea*leenttried*leent4 _`Od _`Od return true _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s /arse*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleenTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# is)ooleanc%ea*leenteleentTail44 arse)ooleanc%ea*leenteleent"d4 else i# istringc%ea*leenteleentTail44 arsetringc%ea*leenteleent"d4 else i# is"ntegerc%ea*leenteleentTail44 _`Ob arse"ntegerc%ea*leenteleent"d4 _`Od else _`Ob t%ro? ne? /arse*>cetion tring.#orat(rguent: c %as in6alid #orat: s., eleent"d, eleentTail4, 04 _`Od _`Od ri6ate 6oid 6alidatec%ea*leent"dc%ar eleent"d4 t%ro?s /arse*>cetion _`Ob i# C%aracter.isLettereleent"d44 _`Ob t%ro? ne? /arse*>cetion )ad c%aracter: Z eleent"d Z in (rgs #orat: Z sc%ea, 04
_`Od _`Od ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob boolean(rgs.uteleent"d, #alse4 _`Od ri6ate 6oid arse"ntegerc%ea*leentc%ar eleent"d4 _`Ob int(rgs.uteleent"d, 04 _`Od ri6ate 6oid arsetringc%ea*leentc%ar eleent"d4 _`Ob string(rgs.uteleent"d, 4 _`Od ri6ate boolean istringc%ea*leenttring eleentTail4 _`Ob return eleentTail.e@uals4 _`Od ri6ate boolean is)ooleanc%ea*leenttring eleentTail4 _`Ob return eleentTail.lengt%4 XX 0 _`Od ri6ate boolean is"ntegerc%ea*leenttring eleentTail4 _`Ob return eleentTail.e@ualsk4 _`Od ri6ate boolean arse(rguents4 t%ro?s (rgs*>cetion _`Ob #or current(rguent X 0 current(rguent ] args.lengt% current(rguentZZ4 _`Ob tring arg X argscurrent(rguentU arse(rguentarg4 _`Od return true _`Od ri6ate 6oid arse(rguenttring arg4 t%ro?s (rgs*>cetion _`Ob i# arg.starts7it%144 arse*leentsarg4 _`Od ri6ate 6oid arse*leentstring arg4 t%ro?s (rgs*>cetion _`Ob #or int i X i ] arg.lengt%4 iZZ4 arse*leentarg.c%ar(ti44 _`Od ri6ate 6oid arse*leentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob i# set(rguentargC%ar44 argsound.addargC%ar4 else _`Ob une>ected(rguents.addargC%ar4 errorCode X *rrorCode.B*+/*CT*-(RGM*BT 6alid X #alse _`Od _`Od ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob i# is)oolean(rgargC%ar44
set)oolean(rgargC%ar, true4 else i# istring(rgargC%ar44 settring(rgargC%ar4 else i# is"nt(rgargC%ar44 set"nt(rgargC%ar4 else return #alse return true _`Od ri6ate boolean is"nt(rgc%ar argC%ar4 _`Ob return int(rgs.contains$e5argC%ar4 _`Od ri6ate 6oid set"nt(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tring araeter X null tr5 _`Ob araeter X argscurrent(rguentU int(rgs.utargC%ar, ne? "ntegeraraeter44 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% Buberorat*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od _`Od ri6ate 6oid settring(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tr5 _`Ob string(rgs.utargC%ar, argscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od ri6ate boolean istring(rgc%ar argC%ar4 _`Ob return string(rgs.contains$e5argC%ar4 _`Od ri6ate 6oid set)oolean(rgc%ar argC%ar, boolean 6alue4 _`Ob boolean(rgs.utargC%ar, 6alue4
_`Od ri6ate boolean is)oolean(rgc%ar argC%ar4 _`Ob return boolean(rgs.contains$e5argC%ar4 _`Od ublic int cardinalit54 _`Ob return argsound.si!e4 _`Od ublic tring usage4 _`Ob i# sc%ea.lengt%4 ^ 04 return 1 Z sc%ea Z U else return _`Od ublic tring errorMessage4 t%ro?s *>cetion _`Ob s?itc% errorCode4 _`Ob case <$: t%ro? ne? *>cetionT"LT: %ould not get %ere.4 case B*+/*CT*-(RGM*BT: return une>ected(rguentMessage4 case M""BGTR"BG: return tring.#oratCould not #ind string araeter #or 1c., error(rguent"d4 case "B(L"-"BT*G*R: return tring.#orat(rguent 1 c e>ects an integer but ?as msh., error(rguent"d, error/araeter4 case M""BG"BT*G*R: return tring.#oratCould not #ind integer araeter #or 1c., error(rguent"d4 _`Od return _`Od ri6ate tring une>ected(rguentMessage4 _`Ob tring)u##er essage X ne? tring)u##er(rguentss4 14 #or c%ar c : une>ected(rguents4 _`Ob essage.aendc4 _`Od essage.aend une>ected.4 return essage.totring4 _`Od ri6ate boolean #alse"#Bull)oolean b4 _`Ob return b X null '' b _`Od ri6ate int !ero"#Bull"nteger i4 _`Ob return i XX null I 0 : i _`Od ri6ate tring blan&"#Bulltring s4 _`Ob return s X null I : s
_`Od ublic tring gettringc%ar arg4 _`Ob return blan&"#Bullstring(rgs.getarg44 _`Od ublic int get"ntc%ar arg4 _`Ob return !ero"#Bullint(rgs.getarg44 _`Od ublic boolean get)ooleanc%ar arg4 _`Ob return #alse"#Bullboolean(rgs.getarg44 _`Od ublic boolean %asc%ar arg4 return argsound.containsarg4 _`Od ublic boolean isalid4 _`Ob return 6alid _`Od ri6ate class (rgs*>cetion e>tends *>cetion _`Ob _`Od _`Od *sero @ue su reacción inicial ante tal cantidad de código es alegrarse or no %aberlo conser6ado tal cual. i %a sido su reacción, recuerde @ue ser= la @ue tengan otros @ue lean un borrador de su código. *n realidad, rier borrador es lo e8or @ue se uede decir sobre este código. *6identeente es un traba8o en rogreso. La cantidad de 6ariables de instancia es aabullante. Cadenas e>tra3as coo FT"LT, as%et 5 Treeet, 5 los blo@ues tr51catc%1 catc% auentan el desastre. Bo era i intención crear este desastre. *n realidad, intentaba antener cierta organi!ación, coo deuestra la elección de nobres de #unciones 5 6ariables, 5 la estructura del rograa. /ero es e6idente @ue el roblea se e #ue de las anos. *l desastre auentó gradualente. Las 6ersiones anteriores no #ueron tan alas. /or e8elo, el Listado V19 uestra una 6ersión inicial en la @ue sólo #uncionaban los arguentos booleanos. !istado F@ (rgs.8a6a sólo arguentos booleanos4 ac&age co.ob8ectentor.utilities.getots iort 8a6a.util. ublic class (rgs _`Ob ri6ate tring sc%ea ri6ate tringU args ri6ate boolean 6alid ri6ate et]C%aracter^ une>ected(rguents X ne? Treeet]C%aracter^4 ri6ate Ma]C%aracter, )oolean^ boolean(rgs X ne? as%Ma]C%aracter, )oolean^4 ri6ate int nuber<#(rguents X 0 ublic (rgstring sc%ea, tringU args4 _`Ob t%is.sc%ea X sc%ea
t%is.args X args 6alid X arse4 _`Od ublic boolean isalid4 _`Ob return 6alid _`Od ri6ate boolean arse4 _`Ob i# sc%ea.lengt%4 XX 0 '' args.lengt% XX 04 return true arsec%ea4 arse(rguents4 return une>ected(rguents.si!e4 XX 0 _`Od ri6ate boolean arsec%ea4 _`Ob #or tring eleent : sc%ea.slit,44 _`Ob arsec%ea*leenteleent4 _`Od return true _`Od ri6ate 6oid arsec%ea*leenttring eleent4 _`Ob i# eleent.lengt%4 XX 4 _`Ob arse)ooleanc%ea*leenteleent4 _`Od _`Od ri6ate 6oid arse)ooleanc%ea*leenttring eleent4 _`Ob c%ar c X eleent.c%ar(t04 i# C%aracter.isLetterc44 _`Ob boolean(rgs.utc, #alse4 _`Od _`Od ri6ate boolean arse(rguents4 _`Ob #or tring arg : args4 arse(rguentarg4 return true _`Od ri6ate 6oid arse(rguenttring arg4 _`Ob i# arg.starts7it%144 arse*leentarg4 _`Od ri6ate 6oid arse*leentstring arg4 _`Ob #or int i X i ] arg.lengt%4 iZZ4 arse*leentarg.c%ar(ti44 _`Od ri6ate 6oid arse*leentc%ar argC%ar4 _`Ob i# is)ooleanargC%ar44 _`Ob nuber<#(rguentsZZ set)oolean(rgargC%ar, true4
_`Od else une>ected(rguents.addargC%ar4 _`Od ri6ate 6oid set)oolean(rgc%ar argC%ar, boolean 6alue4 _`Ob boolean(rgs.utargC%ar, 6alue4 _`Od ri6ate boolean is)ooleanc%ar argC%ar4 _`Ob return boolean(rgs.contains$e5argC%ar4 _`Od ublic int cardinalit54 _`Ob return nuber<#(rguents _`Od ublic tring usage4 _`Ob i# sc%ea.lengt%4 ^ 04 return 1Zsc%eaZU else return _`Od ublic tring errorMessage4 _`Ob i# une>ected(rguents.si!e4 ^ 04 _`Ob return une>ected(rguentMessage4 _`Od else return _`Od ri6ate tring une>ected(rguentMessage4 _`Ob tring)u##er essage X ne? tring)u##er(rguents4 14 #or c%ar c : une>ected(rguents4 _`Ob essage.aendc4 _`Od essage.aend une>ected.4 return essage.totring4 _`Od ublic boolean get)ooleanc%ar arg4 _`Ob return boolean(rgs.getarg4 _`Od _`Od (un@ue %a5 oti6os ara @ue8arse del código, no es tan alo. *s coacto 5 sencillo, 5 #=cil de entender. in ebargo, en este código se arecia la seilla del desastre osterior 5 resulta e6idente or@ué. La 6ersión osterior sólo tiene dos tios de arguentos =s @ue ésta: tring e integer. La inclusión de sólo dos tios =s tiene un treendo iacto negati6o en el código. Lo con6ierte de algo @ue sería ra!onableente antenible en algo @ue seguraente esté lagado de errores. (3adí los dos tios de arguento de #ora increental. /riero, el arguento tring, @ue genera lo siguiente: !istado .<
(rgs.8a6a booleano 5 tring4 ac&age co.ob8ectentor.utilities.getots iort 8a6a.te>t./arse*>cetion iort 8a6a.util. ublic class (rgs _`Ob ri6ate tring sc%ea ri6ate tringU args ri6ate boolean 6alid X true ri6ate et]C%aracter^ une>ected(rguents X ne? Treeet]C%aracter^4 ri6ate Ma]C%aracter, )oolean^ boolean(rgs X ne? as%Ma]C%aracter, )oolean^4 ri6ate Ma]C%aracter, tring^ string(rgs X ne? as%Ma]C%aracter, tring^4 ri6ate et]C%aracter^ argsound X ne? as%et]C%aracter^4 ri6ate int current(rguent ri6ate c%ar error(rguent X m_0h enu *rrorCode _`Ob <$, M""BGTR"BG _`Od ri6ate *rrorCode errorCode X *rrorCode.<$ ublic (rgstring sc%ea, tringU args4 t%ro?s /arse*>cetion _`Ob t%is.sc%ea X sc%ea t%is.args X args 6alid X arse4 _`Od ri6ate boolean arse4 t%ro?s /arse*>cetion _`Ob i# sc%ea.lengt%4 XX 0 '' args.lengt% XX 04 return true arsec%ea4 arse(rguents4 return 6alid _`Od ri6ate boolean arsec%ea4 t%ro?s /arse*>cetion _`Ob #or tring eleent : sc%ea.slit,44 _`Ob i# eleent.lengt%4 ^ 04 _`Ob tring tried*leent X eleent.tri4 arsec%ea*leenttried*leent4 _`Od _`Od return true _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s /arse*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# is)ooleanc%ea*leenteleentTail44 arse)ooleanc%ea*leenteleent"d4 else i# istringc%ea*leenteleentTail44 arsetringc%ea*leenteleent"d4
_`Od ri6ate 6oid 6alidatec%ea*leent"dc%ar eleent"d4 t%ro?s /arse*>cetion _`Ob i# C%aracter.isLettereleent"d44 _`Ob t%ro? ne? /arse*>cetion )ad c%aracter: Z eleent"d Z in (rgs #orat: Z sc%ea, 04 _`Od _`Od ri6ate 6oid arsetringc%ea*leentc%ar eleent"d4 _`Ob string(rgs.uteleent"d, 4 _`Od ri6ate boolean istringc%ea*leenttring eleentTail4 _`Ob return eleentTail.e@uals4 _`Od ri6ate boolean is)ooleanc%ea*leenttring eleentTail4 _`Ob return eleentTail.lengt%4 XX 0 _`Od ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob boolean(rgs.uteleent"d, #alse4 _`Od ri6ate boolean arse(rguents4 _`Ob #or current(rguent X 0 current(rguent ] args.lengt% current(rguentZZ4 _`Ob tring arg X argscurrent(rguentU arse(rguentarg4 _`Od return true _`Od ri6ate 6oid arse(rguenttring arg4 _`Ob i# arg.starts7it%144 arse*leentsarg4 _`Od ri6ate 6oid arse*leentstring arg4 _`Ob #or int i X i ] arg.lengt%4 iZZ4 arse*leentarg.c%ar(ti44 _`Od ri6ate 6oid arse*leentc%ar argC%ar4 _`Ob i# set(rguentargC%ar44 argsound.addargC%ar4 else _`Ob une>ected(rguents.addargC%ar4 6alid X #alse _`Od _`Od ri6ate boolean set(rguentc%ar argC%ar4 _`Ob boolean set X true i# is)ooleanargC%ar44 set)oolean(rgargC%ar, true4
else i# istringargC%ar44 settring(rg argC%ar, 4 else set X #alse return set _`Od ri6ate 6oid settring(rgc%ar argC%ar, tring s4 _`Ob current(rguentZZ tr5 _`Ob string(rgs.utargC%ar, argscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent X argC%ar errorCode X *rrorCode.M""BGTR"BG _`Od _`Od ri6ate boolean istringc%ar argC%ar4 _`Ob return string(rgs.contains$e5argC%ar4 _`Od ri6ate 6oid set)oolean(rgc%ar argC%ar, boolean 6alue4 _`Ob boolean(rgs.utargC%ar, 6alue4 _`Od ri6ate boolean is)ooleanc%ar argC%ar4 _`Ob return boolean(rgs.contains$e5argC%ar4 _`Od ublic int cardinalit54 _`Ob return argsound.si!e4 _`Od ublic tring usage4 _`Ob i# sc%ea.lengt%4 ^ 04 return 1 Z sc%ea Z U else return _`Od ublic tring errorMessage4 t%ro?s *>cetion _`Ob i# une>ected(rguents.si!e4 ^ 04 _`Ob return une>ected(rguentMessage4 _`Od else s?itc% errorCode4 _`Ob case M""BGTR"BG: return tring.#orat Could not #ind string araeter #or 1c., error(rguent4 case <$: t%ro? ne? *>cetionT"LT: %ould not get %ere.4 _`Od return _`Od
ri6ate tring une>ected(rguentMessage4 _`Ob tring)u##er essage X ne? tring)u##er(rguents4 14 #or c%ar c : une>ected(rguents4 _`Ob essage.aendc4 _`Od essage.aend une>ected.4 return essage.totring4 _`Od ublic boolean get)ooleanc%ar arg4 _`Ob return #alse"#Bullboolean(rgs.getarg44 _`Od ri6ate boolean #alse"#Bull)oolean b4 _`Ob return b XX null I #alse : b _`Od ublic tring gettringc%ar arg4 _`Ob return blan&"#Bullstring(rgs.getarg44 _`Od ri6ate tring blan&"#Bulltring s4 _`Ob return s XX null I : s _`Od ublic boolean %asc%ar arg4 _`Ob return argsound.containsarg4 _`Od ublic boolean isalid4 _`Ob return 6alid _`Od _`Od Corobar= @ue eie!a a desbocarse. Bo es terrible ero el desastre se est= gestando. )asta con incluir el tio de arguento integer ara @ue resulte #atídico.
#ntonces me detu+e Toda6ía tenía @ue a3adir otros dos tios de arguentos 5 sabía @ue eeorarían las cosas. i los #or!aba, seguraente #uncionarían ero ro6ocaría un desastre deasiado colicado de arreglar. i la estructura del código tenía @ue oder antenerse, era el oento de corregirla. /or ello de8é de a3adir eleentos 5 coencé la re#actori!ación. Tras a3adir los arguentos tring e integer, sabía @ue cada uno necesitaría nue6o código en tres untos rinciales. *n rier lugar, cada tio de arguento argu ento necesita una #ora de anali!ar su eleento de es@uea ara oder seleccionar el as%Ma de ese tio. Tras ello, sería necesario anali!ar cada tio de arguento en las cadenas de línea de coandos 5 con6ertirlos en su tio correcto. /or ;ltio, cada tio de arguento necesitaría un étodo get+++ ara oder de6ol6erlo al in6ocador coo su tio correcto. Muc%os tios di#erentes 5 todos con étodos siilares, lo @ue en realidad era una clase. E de este odo nació el conceto de (rguentMars%aler.
Sobre el incrementalismo na de las e8ores #oras de acabar con un rograa es reali!ar cabios asi6os con la intención de e8orarlo. (lgunos rograas nunca se recueran de estas e8oras. *l roblea es lo colicado @ue resulta conseguir @ue el rograa #uncione de la isa #ora @ue antes de la e8ora. /ara e6itarlo, recurro a la discilina T-- $est-Driven Development o o -esarrollo guiado or ruebas4. na de las doctrinas centrales de este en#o@ue es antener la e8ecución del sistea en todo oento. *s decir, con T-- no uedo reali!ar cabios @ue a#ecten al #uncionaiento del sistea. Todos los cabios deben antenerlo coo antes de los cabios. /ara lograrlo, necesito una serie de ruebas autoati!adas @ue e8ecutar r=idaente 5 @ue 6eri#i@uen @ue el coortaiento del sistea no %a 6ariado. /ara la clase (rgs, creé una serie de ruebas de unidad 5 acetación. Las ruebas de unidad se crearon en Ja6a 5 se adinistraron con Jnit. Las ruebas de acetación se crearon coo =ginas ?i&i en itBesse. /odría %aber e8ecutado estas ruebas ruebas en cual@uier oento 5, si eran satis#actorias, sabría @ue el sistea #uncionaba de la #ora eseci#icada. (sí ues, coencé a reali!ar e@ue3os cabios. Cada uno desla!aba la estructura del sistea %acia el conceto (rguentMars%aler, 5 cada cabio antenía el #uncionaiento del sistea. *l rier cabio reali!ado #ue a3adir el es@ueleto de (rguentMars%aller al #inal del desastre anterior 6éase el Listado V14. !istado . (rguentMars%aller a3adido a (rgs.8a6a ri6ate class (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse ublic 6oid set)ooleanboolean 6alue4 _`Ob booleanalue X 6alue _`Od ublic boolean get)oolean4 _`Ob return booleanalue _`Od _`Od ri6ate class )oolean(rguentMars%aler e>tends (rguentMars%aler _`Ob _`Od ri6ate class tring(rguentMars%aler e>tends (rguentMars%aler _`Ob _`Od ri6ate class "nteger(rguentMars%aler e>tends (rguentMars%aler _`Ob _`Od _`Od *6identeente, esto no a#ectaría a nada, or lo @ue realicé la odi#icación =s sencilla osible @ue a#ectara a la ínia cantidad de código. Cabié as%Ma ara @ue los arguentos )oolean acetaran (rguentMars%aler. ri6ate Ma]C%aracter, ArgumentMars/aler^ boolean(rgs X ne? as%Ma]C%aracter, ArgumentMars/aler^4 *sto a#ectaba a 6arias instrucciones @ue corregí r=idaente. Y ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob
boolean(rgs.uteleent"d, new (ooleanArgumentMars/aler44 _`Od Y ri6ate 6oid set)oolean(rgc%ar argC%ar, boolean 6alue4 _`Ob boolean(rgs.getargC%ar4.set(oolean6alue4 _`Od Y ublic boolean get)ooleanc%ar arg4 _`Ob return #alse"#Bull boolean(rgs.getarg4.get(ooleanR4 _`Od *stos cabios se alican a las !onas @ue encionaos antes: arse, set 5 get ara el tio de arguento. -esa#ortunadaente, aun@ue sean cabios enores, algunas de las ruebas coen!aron a #allar. # allar. i se #i8a atentaente en get)oolean, corobar= @ue se uede in6ocar con 5 ero no n o e>iste un arguento 5, or lo @ue boolean(rgs.getm5h4 boolean(rgs.ge tm5h4 de6ol6er= null 5 la #unción generar= Bull/ointer*>cetion. La #unción #alse"#Bull se usa coo rotección ante este %ec%o ero el cabio alicado %ace @ue la #unción sea irrele6ante. *l increentaliso e>igía @ue esto #uncionara antes de reali!ar otros cabios. La solución no era deasiado colicada bastaba con cabiar la corobación de null. Ea no era necesario corobar null en boolean, sino en (rguentMars%aller. /riero, eliiné la in6ocación de #alse"#Bull en la #unción get)oolean. Ea no ser6ía de nada, or lo @ue eliiné directaente la #unción. Las ruebas seguían #allando igual, lo @ue suonía @ue no %abía nue6os errores. ublic boolean get)ooleanc%ar arg4 _`Ob return boolean(rgs.getarg4.get)oolean4 _`Od Tras ello, di6idí la #unción en dos líneas 5 a3adí (rguentMars%aller a una 6ariable roia: arguentMars%aller. Bo e reocuaba el e>tenso nobre de la 6ariable era redundante 5 estorbaba a la #unción, or lo @ue lo redu8e a a BU. ublic boolean get)ooleanc%ar arg4 _`Ob (rgs.(rguentMars%aler am X boolean(rgs.getarg4 return am.get)oolean4 _`Od E tras ello a3adí la lógica de detección de null. ublic boolean get)ooleanc%ar arg4 _`Ob (rgs.(rguentMars%aler a X boolean(rgs.getarg4 return am Q null XX a.get)oolean4 _`Od
Argumentos de cadena La inclusión de los arguentos tring #ue siilar a la de los arguentos boolean. Tu6e @ue cabiar as%Ma 5 conseguir @ue #uncionaran arse, set 5 get. Bo deberían roducirse sorresas osteriores a e>ceción de @ue la ileentación coleta se incluía en la clase (rguentMars%aller en lugar de distribuirla en 6ariantes. ri6ate Ma]C%aracter, ArgumentMars/aler^ string(rgs X
ne? as%Ma]C%aracter, ArgumentMars/aler^4 Y ri6ate 6oid arsetringc%ea*leentc%ar eleent"d4 _`Ob string(rgs.uteleent"d, ne? tring(rguentMars%aler44 _`Od Y ri6ate 6oid settring(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tr5 _`Ob string(rgs.getargC%ar4.setStringargscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od Y ublic tring gettring c%ar arg4 _`Ob Args.ArgumentMars/aler am Q string(rgs.getarg4 return am QQ null ' _` : a.gettring4 _`Od Y ri6ate class (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse pri+ate String stringKalueT ublic 6oid set)ooleanboolean 6alue4 _`Ob booleanalue X 6alue _`Od ublic boolean get)oolean4 _`Ob return booleanalue _`Od public +oid setStringRString s ]^=b stringKalue Q sT ]^=d public String getStringR ]^=b return stringKalue QQ null ' _` H stringKalueT ]^=d
_`Od -e nue6o, estos cabios se reali!aron indi6idualente ara conser6ar las ruebas, aun@ue #allaran. i una rueba #allaba, e aseguraba de @ue #uera correcta antes de continuar con el siguiente cabio. Ea debería reconocer i intención. Tras incluir el coortaiento de se3ali!ación en la clase base (rguentMars%aler, coencé a trans#erirlo a las 6ariantes, ara de esta #ora antener el #uncionaiento ientras cabiaba gradualente la #ora del rograa.
*l siguiente aso consistía en trans#erir la #uncionalidad del arguento int a (rguentMars%aler. -e nue6o, no %ubo sorresas. ri6ate Ma]C%aracter, ArgumentMars/aler^ int(rgs X ne? as%Ma]C%aracter, ArgumentMars/aler^4 Y ri6ate 6oid arse"ntegerc%ea*leentc%ar eleent"d4 _`Ob int(rgs.uteleent"d, new IntegerArgumentMars/alerR4 _`Od Y ri6ate 6oid set"nt(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tring araeter X null tr5 _`Ob araeter X argscurrent(rguentU int(rgs.getargC%ar4.setInteger"nteger.arse"ntaraeter44 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% Buberorat*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od _`Od Y ublic int get"ntc%ar arg4 _`Ob Args.ArgumentMars/aler am Q int(rgs.getarg4 return am QQ null ' < : a.get"nteger 4 _`Od Y ri6ate class (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse ri6ate tring stringalue pri+ate int integerKalueT
ublic 6oid set)ooleanboolean 6alue4 _`Ob booleanalue X 6alue _`Od ublic boolean get)oolean4 _`Ob return booleanalue _`Od ublic 6oid settringtring s4 _`Ob stringalue X s
_`Od ublic tring gettring4 _`Ob return stringalue XX null I : stringalue _`Od public +oid setIntegerRint i ]^=b
integerKalue Q iT ]^=d public int getIntegerR ]^=b
return integerKalueT ]^=d
_`Od Tras trans#erir la se3ali!ación a (rguentMars%aler, coencé a trans#erir la #uncionalidad a las 6ariantes. *l rier aso #ue asar la #unción set)oolean a )oolean(rguentMars%aller 5 garanti!ar su correcta in6ocación. /ara ello creé un étodo set abstracto. ri6ate abstract class (rguentMars%aler _`Ob protected boolean booleanalue X #alse ri6ate tring stringalue ri6ate int integeralue ublic 6oid set)ooleanboolean 6alue4 _`Ob booleanalue X 6alue _`Od ublic boolean get)oolean4 _`Ob return booleanalue _`Od ublic 6oid settringtring s4 _`Ob stringalue X s _`Od ublic tring gettring4 _`Ob return stringalue XX null I : stringalue _`Od ublic 6oid set "ntegerint i4 _`Ob integeralue X i _`Od ublic int get"nteger4 _`Ob return integeralue _`Od public abstract +oid setRString sT
_`Od Tras ello, ileenté el étodo set en )oolean(rguentMars%aller. ri6ate class )oolean(rguentMars%aler e>tends (rguentMars%aler _`Ob public +oid setRString s ]^=b
booleanKalue Q trueT ]^=d
_`Od E or ;ltio cabié la in6ocación de set)oolean or la de set. ri6ate 6oid set)oolean(rgc%ar argC%ar, boolean 6alue4 _`Ob boolean(rgs.getargC%ar4.setR_true` _`Od Las ruebas seguían siendo satis#actorias. Coo este cabio %acía @ue set se ileentara en )oolean(rguentMars%aler, eliiné el étodo set)oolean de la clase base (rguentMars%aler. La #unción abstracta set aceta un arguento tring ero la ileentación de )oolean(rguentMars%aler no lo usa. e incluido el arguento or@ue sabía @ue tring(rguentMars%aler e "nteger(rguentMars%aler lo utili!arían. Tras ello, el ob8eti6o era ileentar el étodo get en )oolean(rguentMars%aler. La ileentación de #unciones get siere es escabrosa 5a @ue el tio de6uelto tiene @ue ser tends (rguentMars%aler _`Ob ublic 6oid set tring s4 _`Ob booleanalue X true _`Od public Ob)ect getR ]^=b return booleanKalueT ]^=d _`Od -e nue6o, las ruebas son satis#actorias. (%ora tanto get coo set se ileentan en )oolean(rguentMars%aler. *sto e erite eliinar la antigua #unción get)oolean de
(rguentMars%aler, cabiar la 6ariable rotegida booleanalue a )oolean(rguentMars%aler 5 con6ertirla en ri6ada. Reetí el iso atrón de cabios con las cadenas. "leenté set 5 get, eliiné las #unciones sin usar 5 deslacé las 6ariables. ri6ate 6oid settring(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tr5 _`Ob string(rgs.getargC%ar4.setargscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od Y ublic tring gettringc%ar arg4 _`Ob (rgs.(rguentMars%aler a X string(rgs.getarg4 return a XX null I : RString a.get4 _`Od Y ri6ate abstract class (rguentMars%aler _`Ob ri6ate int integeralue ublic 6oid set"ntegerint i4 _`Ob integeralue X i _`Od ublic int get"nteger4 _`Ob return integeralue _`Od ublic abstract 6oid settring s4 ublic abstract tends (rguentMars%aler _`Ob pri+ate boolean booleanKalue Q falseT
ublic 6oid settring s4 _`Ob booleanalue X true _`Od ublic tends (rguentMars%aler _`Ob pri+ate String stringKalue Q _`T ublic 6oid settring s4 _`Ob stringKalue Q sT
_`Od ublic
_`Od _`Od ri6ate class "nteger(rguentMars%aler e>tends (rguentMars%aler _`Ob ublic 6oid settring s4_`Ob _`Od ublic ceción, ero el resultado es =s indicado 5a @ue el conceto de Buberorat*>cetion se oculta totalente en "nteger(rguentMars%aler. ri6ate boolean is"nt(rgc%ar argC%ar4 _`Ob return int(rgs.contains$e5argC%ar4 _`Od ri6ate 6oid set"nt(rgc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tring araeter X null tr5 _`Ob araeter X argscurrent(rguentU int(rgs.getargC%ar4.setaraeter4 _`Od catc% (rra5"nde>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% Args#Eception e4 _`Ob 6alid X #alse error(rguent"d X argC%ar error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? e _`Od _`Od Y ri6ate 6oid set)oolean(rgc%ar argC%ar4 _`Ob tr- ]^=b
boolean(rgs.getargC%ar4.settrue4 ]^=d catc/ RArgs#Eception e ]^=b ]^=d
_`Od Y ublic int get"ntc%ar arg4 _`Ob (rgs.(rguentMars%aler a X int(rgs.getarg4 return a XX null I 0 : RInteger a.get4 _`Od Y ri6ate abstract class (rguentMars%aler _`Ob ublic abstract 6oid settring s4 t%ro?s (rgs*>cetion ublic abstract tends (rguentMars%aler _`Ob pri+ate int intKalue Q
_`Od _`Od *6identeente, las ruebas seguían #uncionando. Tras ello, e des%ice de las distintas asignaciones de la arte suerior del algorito, lo @ue %ace @ue el sistea sea uc%o =s genérico. in ebargo, no las uede eliinar 5a @ue a#ectaría a la integridad del sistea. *n su lugar, a3adí un nue6o Ma ara (rguentMars%aler 5, tras ello, cabié uno a uno los étodos ara @ue usaran la nue6a asignación en lugar de las originales. ublic class (rgs _`Ob Y ri6ate Ma]C%aracter, (rguentMars%aler^ boolean(rgs X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate Ma]C%aracter, (rguentMars%aler^ string(rgs X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate Ma]C%aracter, (rguentMars%aler^ int(rgs X ne? as%Ma]C%aracter, (rguentMars%aler^4 pri+ate MapVC/aracter* ArgumentMars/alerW mars/alers Q new "as/MapVC/aracter* ArgumentMars/alerWRT Y ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob
ArgumentMars/aler m Q now (ooleanArgumentMars/alerRT boolean(rgs.uteleent"d, 4 mars/alers.putRelementId* mT
_`Od ri6ate 6oid arse"ntegerc%ea*leentc%ar eleent"d4 _`Ob ArgumentMars/aler m Q new IntegerArgumentMars/alerRT int(rgs.uteleent"d, 4 mars/alers.putRelementId* mT
_`Od ri6ate 6oid arsetringc%ea*leentc%ar eleent"d4 _`Ob ArgumentMars/aler m Q new StringArgumentMars/alerRT string(rgs.uteleent"d, 4 mars/alers.putRelementId* mT
_`Od Las ruebas seguían #uncionando. Tras ello, cabié is)oolean(rg de esto: ri6ate boolean is)oolean(rgc%ar argC%ar4 _`Ob return boolean(rgs.contains$e5argC%ar4 _`Od a este otro: ri6ate boolean is)oolean(rgc%ar argC%ar4 _`Ob ArgumentMars/aler m Q mars/alers.getRargC/arT return m instanceof (ooleanArgumentMars/alerT
_`Od Las ruebas #uncionaban, or lo @ue ali@ué el iso cabio en is"nt(rg e istring(rg. ri6ate boolean is"nt(rgc%ar argC%ar4 _`Ob ArgumentMars/aler m Q mars/alers.getRargC/arT return m instanceof IntegerArgumentMars/alerT _`Od ri6ate boolean istring(rgc%ar argC%ar4 _`Ob ArgumentMars/aler m Q mars/alers.getRargC/arT return m instanceof StringArgumentMars/alerT _`Od Las ruebas eran correctas, or lo @ue eliiné las in6ocaciones dulicadas de ars%alers.get: ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob ArgumentMars/aler m Q mars/alers.getRargC/arT
i# is)oolean(rgm44 set)oolean(rgargC%ar4 else i# istring(rgm44 settring(rgargC%ar4 else i# is"nt(rgm44 set"nt(rgargC%ar4 else return #alse return true _`Od ri6ate boolean is"nt(rg ArgumentMars/aler m4 _`Ob return instanceo# "nteger(rguentMars%aler _`Od ri6ate boolean istring(rg ArgumentMars/aler m4 _`Ob return instanceo# tring(rguentMars%aler _`Od ri6ate boolean is)oolean(rg ArgumentMars/aler m4 _`Ob return instanceo# )oolean(rguentMars%aler _`Od Los tres arguentos is>>>(rg 5a no tenían sentido, de odo @ue los reubi@ué: ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# m instanceof (ooleanArgumentMars/aler4 set)oolean(rgargC%ar4 else i# m instanceof StringArgumentMars/aler4 settring(rgargC%ar4 else i# m instanceof IntegerArgumentMars/aler4 set"nt(rgargC%ar4 else return #alse return true _`Od Tras ello, eecé a usar la asignación ars%alers en las #unciones set, di6idiendo el uso de las otras tres asignaciones. Coencé or los eleentos boolean. ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# instanceo# )oolean(rguentMars%aler4 set)oolean(rgm4 else i# instanceo# tring(rguentMars%aler4 settring(rgargC%ar4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rgargC%ar4 else return #alse return true _`Od Y
ri6ate 6oid set)oolean(rgArgumentMars/aler m4 _`Ob tr5 _`Ob m.settrue4 eraH booleanArgs.getRargC/ar.setR_true`T _`Od catc% (rgs*>cetion e4 _`Ob _`Od _`Od Las ruebas seguían siendo correctas de odo @ue reetí la oeración con las cadenas 5 los enteros. -e esta anera se uede integrar arte del desagradable código de gestión de e>ceciones en la #unción set(rguent. ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 tr- ]^=b
i# instanceo# )oolean(rguentMars%aler4 set)oolean(rg4 else i# instanceo# tring(rguentMars%aler4 settring(rgm4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rgm4 else return #alse ]^=d catc/ RArgs#Eception e ]^=b
+alid Q falseT errorArgumentId Q argC/arT t/row eT ]^=d
return true _`Od ri6ate 6oid set"nt(rgArgumentMars/aler m4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tring araeter X null tr5 _`Ob araeter X argscurrent(rguentU m.setaraeter4 _`Od catc% (rra5"nde>cetion e4 _`Ob errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% (rgs*>cetion e4 _`Ob error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? e _`Od _`Od ri6ate 6oid settring(rgArgumentMars/aler m4 t%ro?s (rgs*>cetion _`Ob
current(rguentZZ tr5 _`Ob m.setargscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od Ea odía eliinar las tres asignaciones antiguas. /riero, debía cabiar la #unción get)oolean de: ublic boolean get)ooleanc%ar arg4 _`Ob (rgs.(rguentMars%aler a X boolean(rgs.getarg4 return a X null '' )oolean4 a.get4 _`Od a: ublic boolean get)ooleanc%ar arg4 _`Ob (rgs.(rguentMars%aler a X ars%alers.getarg4 boolean b Q falseT tr- ]^=b
b X a X null '' )oolean4 a.get4 ]^=d catc/ RClassCast#Eception e ]^=b b Q falseT ]^=d return bT
_`Od *ste ;ltio cabio uede arecer sorrendente. H/or @ué de reente decidí en#rentare a ClassCast*>cetionI /or tener una serie de ruebas de unidad 5 otra serie indeendiente de ruebas de acetación creadas en itBesse. Las ruebas de itBesse garanti!an @ue si se in6oca get)oolean en un arguento no )ooleano, se obtiene #alse. Bo sucede lo iso con las ruebas de unidad. asta el oento, sólo %abía e8ecutado las ruebas de unidad9WU. *ste ;ltio cabio e eritió e>traer otro uso de la asignación boolean: ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob (rguentMars%aler X ne? )oolean(rguentMars%aler4 booleanArgs.putRelementId* mT
ars%alers.uteleent"d, 4 _`Od E a%ora 5a odeos eliinar la asignación boolean. ublic class (rgs _`Ob Y pri+ate MapVC/aracter* ArgumentMars/alerW booleanArgs Q new "as/MapVC/aracter* ArgmentMars/alerWRT
ri6ate Ma]C%aracter, (rguentMars%aler^ string(rgs X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate Ma]C%aracter, (rguentMars%aler^ int(rgs X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 Y Tras ello, cabié los arguentos tring e "nteger de la isa #ora 5 liié los 6alores boolean. ri6ate 6oid arse)ooleanc%ea*leentc%ar eleent"d4 _`Ob ars%alers.uteleent"d, new (ooleanArgumentMars/alerR4 _`Od ri6ate 6oid arse"ntegerc%ea*leentc%ar eleent"d4 _`Ob ars%alers.uteleent"d, new IntegerArgumentMars/alerR4 _`Od ri6ate 6oid arsetringc%ea*leentc%ar eleent"d4 _`Ob ars%alers.uteleent"d, new StringArgumentMars/alerR4 _`Od Y ublic tring gettringc%ar arg4 _`Ob (rgs.(rguentMars%aler a X mars/alers.getarg4 tr- ]^=b
return a null I : tring4 a.get4 ]^=d catc/ RClassCast#Eception e ]^=b return _`T ]^=d _`Od ublic int get"ntc%ar arg4 _`Ob (rgs.(rguentMars%aler a X mars/alers.getarg4 tr- ]^=b return a XX null I 0 : "nteger4 a.get4 ]^=d catc/ R#Eception e ]^=b return 0 ]^=d
_`Od Y ublic class (rgs _`Ob Y pri+ate MapVC/aracter* ArgumentMars/alerW stringArgs Q new "as/MapVC/aracter* ArgumentMars/alerWRT pri+ate MapVC/aracter* ArgumentMars/alerW intArgs Q new "as/MapVC/aracter* ArgumentMars/alerWRT
ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 Y eguidaente, disuse en línea los tres étodos arse 5a @ue no ser6ían ara uc%o: ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s /arse*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# is)ooleanc%ea*leenteleentTail44 mars/alers.putRelementId* new (ooleanArgumentMars/alerRT else i# istringc%ea*leenteleentTail44 mars/alers.putRelementId* new StringArgumentMars/aler RT else i# is"ntegerc%ea*leenteleentTail44 _`Ob mars/alers.putRelementId* new IntegerArgumentMars/alerRT _`Od else _`Ob t%ro? ne? /arse*>cetiontring.#orat (rguent: c %as in6alid #orat: s., eleent"d, eleentTail4, 04 _`Od _`Od *s el oento de 6er la estructura coleta. *l Listado V12 uestra la clase (rgs actual. !istado F (rgs.8a6a tras la riera re#actori!ación4 ac&age co.ob8ectentor.utilities.getots iort 8a6a.te>t./arse*>cetion iort 8a6a.util. ublic class (rgs _`Ob ri6ate tring sc%ea ri6ate tringU args ri6ate boolean 6alid X true ri6ate et]C%aracter^ une>ected(rguents X ne? Treeet]C%aracter^4 ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate et]C%aracter^ argsound X ne? as%et]C%aracter^4 ri6ate int current(rguent ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X T"LT ri6ate *rrorCode errorCode X *rrorCode.<$ ri6ate enu *rrorCode _`Ob <$, M""BGTR"BG, M""BG"BT*G*R, "B(L"-"BT*G*R,
B*+/*CT*-(RGM*BT_`Od ublic (rgstring sc%ea, tringU args4 t%ro?s /arse*>cetion _`Ob t%is.sc%ea X sc%ea t%is.args X args 6alid X arse4 _`Od ri6ate boolean arse4 t%ro?s /arse*>cetion _`Ob i# sc%ea.lengt%4 XX 0 '' args.lengt% XX 04 return true arsec%ea4 tr5 _`Ob arse(rguents4 _`Od catc% (rgs*>cetion e4 _`Ob _`Od return 6alid _`Od ri6ate boolean arsec%ea4 t%ro?s /arse*>cetion _`Ob #or tring eleent : sc%ea.slit,44 _`Ob i# eleent.lengt%4 ^ 04 _`Ob tring tried*leent X eleent.tri4 arsec%ea*leenttried*leent4 _`Od _`Od return true _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s /arse*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# is)ooleanc%ea*leenteleentTail44 ars%alers.uteleent"d, ne? )oolean(rguentMars%aler44 else i# istringc%ea*leenteleentTail44 ars%alers.uteleent"d, ne? tring(rguent7ars%aler44 else i# is"ntegerc%ea*leenteleentTail44 _`Ob ars%alers.uteleent"d, ne? "nteger(rguentMars%aler44 _`Od else _`Ob t%ro? ne? /arse*>cetiontring.#orat (rguent: c %as in6alid #orat: s., eleent"d, eleentTail4, 04 _`Od _`Od ri6ate 6oid 6alidatec%ea*leent"dc%ar eleent"d4 t%ro?s /arse*>cetion _`Ob i# C%aracter.isLettereleent"d44 _`Ob t%ro? ne? /arse*>cetion )ad c%aracter: Z eleent"d Z in (rgs #orat: Z sc%ea, 04 _`Od _`Od ri6ate boolean istringc%ea*leenttring eleentTail4 _`Ob
return eleentTail.e@uals4 _`Od ri6ate boolean is)ooleanc%ea*leenttring eleentTail4 _`Ob return eleentTail.lengt%4 XX 0 _`Od ri6ate boolean is"ntegerc%ea*leenttring eleentTail4 _`Ob return eleentTail.e@ualsk4 _`Od ri6ate boolean arse(rguents4 t%ro?s (rgs*>cetion _`Ob #or current(rguentX0 current(rguent]args.lengt% current(rguentZZ4 _`Ob tring arg X argscurrent(rguentU arse(rguentarg4 _`Od return true _`Od ri6ate 6oid arse(rguenttring arg4 t%ro?s (rgs*>cetion _`Ob i# arg.starts7it%144 arse*leentsarg4 _`Od ri6ate 6oid arse*leentstring arg4 t%ro?s (rgs*>cetion _`Ob #or int i X i ] arg.lengt%4 iZZ4 arse*leentarg.c%ar(ti44 _`Od ri6ate 6oid arse*leentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob i# set(rguentargC%ar44 argsound.addargC%ar4 else _`Ob une>ected(rguents.addargC%ar4 errorCode X *rrorCode.B*+/*CT*-(RGM*BT 6alid X #alse _`Od _`Od ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 tr5 _`Ob i# instanceo# )oolean(rguentMars%aler4 set)oolean(rg4 else i# instanceo# tring(rguentMars%aler4 settring(rg4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rg4 else return #alse _`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e
_`Od return true _`Od ri6ate 6oid set"nt(rg(rguentMars%aler 4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tring araeter X null tr5 _`Ob araeter X argscurrent(rguentU .setaraeter4 _`Od catc% (rra5"nde>cetion e4 _`Ob errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% (rgs*>cetion e4 _`Ob error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? e _`Od _`Od ri6ate 6oid settring(rg(rguentMars%aler 4 t%ro?s (rgs*>cetion _`Ob current(rguentZZ tr5 _`Ob .set argscurrent(rguentU4 argscurrent(rguentU4 _`Od catc% (rra5"nde>cetion e4 _`Ob errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od ri6ate 6oid set)oolean(rg(rguentMars%aler 4 _`Ob tr5 _`Ob .settrue4 _`Od catc% (rgs*>cetion e4 _`Ob _`Od _`Od ublic int cardinalit54 _`Ob return argsound.si!e4 _`Od ublic tring usage4 _`Ob i# sc%ea.lengt%4 ^ 04 return X 1 Z sc%ea Z U else return _`Od ublic tring errorMessage4 t%ro?s *>cetion _`Ob s?itc% errorCode4 _`Ob case <$: t%ro? ne? *>cetionT"LT: %ould not get %ere.4 case B*+/*CT*-(RGM*BT:
return une>ected(rguentMessage4 case M""BGTR"BG: return tring.#oratCould not #ind string araeter #or 1c., error(rguent"d4 case "B(L"-"BT*G*R: return tring.#orat(rguent 1c e>ects an integer but ?as msh., error(rguent"d, error/araeter4 case M""BG"BT*G*R: return tring.#oratCould not #ind integer araeter #or 1c., error(rguent"d4 _`Od return _`Od ri6ate tring une>ected(rguentMessage4 _`Ob tring)u##er essage X ne? tring)u##er(rguents4 14 #or _`Obc%ar c : une>ected(rguents4 _`Ob essage.aendc4 _`Od essage.aend une>ected.4 return essage.totring4 _`Od ublic boolean get)ooleanc%ar arg4 _`Ob (rgs.(rguentMars%aler a X ars%alers.getarg4 boolean b X #alse tr5 _`Ob b X a X null '' )oolean4 a.get4 _`Od catc% ClassCast*>cetion e4 _`Ob b X #alse _`Od return b _`Od ublic tring gettringc%ar arg4 _`Ob (rgs.(rguentMars%aler a X ars%alers.get arg4 tr5 _`Ob return a XX null I : tring4 a.get4 _`Od catc% ClassCast*>cetion e4 _`Ob return _`Od _`Od ublic int get"ntc%ar arg4 _`Ob (rgs.(rguentMars%aler a X ars%alers.getarg4 tr5 _`Ob return a XX null I 0 : "nteger4 a.get4 _`Od catc% *>cetion e4 _`Ob return 0 _`Od _`Od
ublic boolean %asc%ar arg4 _`Ob return argsound.containsarg4 _`Od ublic boolean isalid4 _`Ob return 6alid _`Od ri6ate class (rgs*>cetion e>tends *>cetion _`Ob _`Od ri6ate abstract class (rguentMars%aler _`Ob ublic abstract 6oid settring s4 t%ro?s (rgs*>cetion ublic abstract tends (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse ublic 6oid settring s4 _`Ob booleanalue X true _`Od ublic tends (rguentMars%aler _`Ob ri6ate tring stringalue X ublic 6oid settring s4 _`Ob stringalue X s _`Od ublic tends (rguentMars%aler _`Ob ri6ate int intalue X 0 ublic 6oid settring s4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob intalue X "nteger.arse"nts4 _`Od catc% Buberorar*>cetion e4 _`Ob t%ro? ne? (rgs*>cetion4 _`Od _`Od ublic
Toda6ía nos @ueda uc%o traba8o or %acer. Mi intención es eliinar el caso de tios de set(rguent G2WU 5 @ue sólo inclu5a una in6ocación a (rguentMars%aler.set. /ara ello, debo desla!ar set"nt(rg, settring(rg 5 set)oolean(rg a las corresondientes 6ariantes de (rguentMars%aler. /ero %a5 un roblea. i se #i8a atentaente en set"nt(rg, corobar= @ue usa dos 6ariables de instancia: args 5 current(rg. /ara desla!ar set"nt(rg %asta )oolean(rguentMars%aler, tengo @ue asar args 5 current(rgs coo arguentos de #unción. Mu5 desagradable desagr adable U. Resultaría =s indicado asar un arguento 5 no dos. (#ortunadaente, la solución es sencilla. /odeos con6ertir la atri! args en list 5 asar "terator a las #unciones set. /ara el siguiente cabio necesité die! asos, 5 suerar todas las ruebas tras cada uno. /ero sólo ostrareos el resultado. -ebería deterinar la a5oría de estos e@ue3os asos. ublic class (rgs _`Ob ri6ate tring sc%ea pri+ate String;> argsT
ri6ate boolean 6alid X true ri6ate et]C%aracter^ une>ected(rguents X ne? Treeet]C%aracter^4 ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate et]C%aracter^ argsound X ne? as%et]C%aracter^4 ri6ate IteratorVStringW current(rguent ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X T"LT ri6ate *rrorCode errorCode X *rrorCode.<$ pri+ate !istVStringW args!istT
ri6ate enu *rrorCode _`Ob <$, M""BGTR"BG, M""BG"BT*G*R, "B(L"-"BT*G*R, B*+/*CT*-(RGM*BT _`Od ublic (rgstring sc%ea. tringU args4 t%ro?s /arse*>cetion _`Ob t%is.sc%ea X sc%ea args!ist Q Arra-s.as!istRargsT
6alid X arse 4 _`Od ri6ate boolean arse4 t%ro?s /arse*>cetion _`Ob i# sc%ea.lengt%4 XX 0 '' args!ist.sizeR XX 04 return true arsec%ea4 tr5 _`Ob arse(rguents4 _`Od catc% (rgs*>cetion e4 _`Ob _`Od return 6alid _`Od
Y ri6ate boolean arse(rguents4 t%ro?s (rgs*>cetion _`Ob #or current(rguent X args!ist.iteratorRT current(rguent./asBeEtR4 _`Ob tring arg X current(rguent.neEtR arse(rguentarg4 _`Od return true _`Od Y ri6ate 6oid set"nt(rg(rguentMars%aler 4 t%ro?s (rgs*>cetion _`Ob tring araeter X null tr5 _`Ob araeter X current(rguent.neEtR .setaraeter4 _`Od catc% BoSuc/#lement#Eception e4 _`Ob errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% (rgs*>cetion e4 _`Ob error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? e _`Od _`Od ri6ate 6oid settring(rg(rguentMars%aler 4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob .set current(rguent.neEtR4 _`Od catc% BoSuc/#lement#Eception e4 _`Ob errorCode X *rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od on e@ue3os cabios @ue conser6an el #uncionaiento de las ruebas. (%ora odeos ee!ar a desla!ar las #unciones set a las corresondientes 6ariantes. 6 ariantes. /riero, debeos reali!ar el siguiente cabio en set(rguent: ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 if Rm QQ null
return falseT
tr5 _`Ob i# instanceo# )oolean(rguentMars%aler4 set)oolean(rg4 else i# instanceo# tring(rguentMars%aler4 settring(rg4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rg4
else return falseT _`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e _`Od return true _`Od *s un cabio iortante 5a @ue @uereos eliinar totalente la cadena i#1else. /or tanto, debeos e>cluir la condición de error. Ea odeos ee!ar a desla!ar las #unciones set. La #unción set)oolean(rg es tri6ial, de odo @ue la rearareos en rier lugar. *l ob8eti6o es cabiar la #unción set)oolean(rg ara redirigirla a )oolean(rguentMars%aler. ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 return #alse tr5 _`Ob i# instanceo# )oolean(rguentMars%aler4 set)oolean(rg, currentArgument4 else i# instanceo# tring(rguentMars%aler4 settring(rg4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rg4 _`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e _`Od return true _`Od 111 ri6ate 6oid set)oolean(rg (rguentMars%aler , IteratorVStringW currentArgument t%ro?s (rgs*>cetion _`Ob tr- ]^=b
.settrue4 catc/ RArgs#Eception e ]^=b ]^=d
_`Od HBo acabaos de incluir el rocesaiento de e>cecionesI (3adir eleentos ara desués e>cluirlos es %abitual en los rocesos de re#actori!ación. Los asos reducidos 5 la necesidad de @ue las ruebas sigan siendo correctas ilican @ue los eleentos cabien de osición. La re#actori!ación es coo resol6er res ol6er el cubo de Rubi&. e necesitan uc%os asos aso s e@ue3os ara lograr un ob8eti6o o b8eti6o a5or. Cada aso %abilita el siguiente. e reguntar= or @ué asaos iterator si set)oolean(rg no lo necesita. /ues or@ue set"nt(rg 5 settring(rg sí. E coo el ob8eti6o es ileentar las tres #unciones a tra6és de un étodo abstracto en (rguentMars%aller, es necesario asarlo a set)oolean(rg. (%ora set)oolean(rg no sir6e de nada. i %ubiera una #unción set en (rguentMars%aler, odríaos in6ocarla directaente. *s el oento de crear dic%a #unción. *l rier aso consiste en a3adir el nue6o étodo abstracto a (rguentMars%aler. ri6ate abstract class (rguentMars%aler _`Ob public abstract +oid setRIteratorVStringW currentArgument t/rows Args#EceptionT ublic abstract 6oid set tring s4 t%ro?s (rgs*>cetion ublic abstract tends (rguentMars%aler _`Ob ri6ate boolean booleanalue X #alse public +oid setRIteratorVStringW currentArgument t/rows Args#Eception ]^=b
booleanKalue Q trueT
_`Od ublic 6oid settring s4 _`Ob booleanKalue Q trueT
_`Od ublic tends (rguentMars%aler _`Ob ri6ate tring stringalue X public +oid setRIteratorVStringW currentArgument t/rows Args#Eception ]^=b ]^=d
ublic 6oid settring s4 _`Ob stringalue X s _`Od
ublic tends (rguentMars%aler _`Ob ri6ate int intalue X 0 public +oid setRIteratorVStringW currentArgument t/rows Args#Eception ]^=b ]^=d
ublic 6oid settring s4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob intalue X "nteger.arse"nts4 _`Od catc% Buberorat*>cetion e4 _`Ob t%ro? ne? (rgs*>cetion4 _`Od _`Od ublic cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 return #alse tr5 _`Ob i# instanceo# )oolean(rguentMars%aler4 m.setcurrent(rguent4 else i# instanceo# tring(rguentMars%aler4 settring(rg4 else i# instanceo# "nteger(rguentMars%aler4 set"nt(rg4 _`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e _`Od return true _`Od Las ruebas siguen siendo satis#actorias 5 la #unción set se ileenta en )oolean (rguentMars%aler. /odeos reetir la oeración con las cadenas 5 los enteros. ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 return #alse tr5 _`Ob i# instanceo# )oolean(rguentMars%aler4
.setcurrent(rguent4 else i# instanceo# tring(rguentMars%aler4 m.setRcurrentArgumentT else i# instanceo# "nteger(rguentMars%aler4 m.setRcurrentArgumentT
_`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e _`Od return true _`Od 111 ri6ate class tring(rguentMars%aler e>tends (rguentMars%aler _`Ob ri6ate tring stringalue X ublic 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob tr- ]^=b stringKalue Q currentArgument.neEtRT ]^=d catc/ RBoSuc/#lement#Eception e ]^=b
errorCode Q #rrorCode.MISSIBZS34IBT t/row new Args#EceptionRT ]^=d
_`Od ublic 6oid settring s4_`Ob _`Od ublic tends (rguentMars%aler _`Ob ri6ate int intalue X 0 ublic 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob String parameter Q nullT tr- ]^=b parameter Q currentArgument.neEtRT setRparameterT ]^=d catc/ RBoSuc/#lement#Eception e ]^=b errorCode Q #rrorCode.MISSIBZIB3##4T t/row new Args#EceptionRT ]^=d catc/ RArgs#Eception e ]^=b errorParameter Q parameterT errorCode Q #rrorCode.IBKA!I2ZIB3##4T
t/row eT ]^=d
_`Od ublic 6oid settring s4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob intalue X "nteger.arse"nts4 _`Od catc% Buberorat*>cetion e4 _`Ob t%ro? ne? (rgs*>cetion4 _`Od _`Od ublic cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 return #alse tr5 _`Ob .setcurrent(rguent4 return true _`Od catc% (rgs*>cetion e4 _`Ob 6alid X #alse error(rguent"d X argC%ar t%ro? e _`Od _`Od Ea odeos des%acernos de las #unciones de "nteger(rguentMars%aler 5 liiar el resto. ri6ate class "nteger(rguentMars%aler e>tends (rguentMars%aler _`Ob ri6ate int intalue X 0 ublic 6oid set "terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob tring araeter X null tr5 _`Ob araeter X current(rguent.ne>t4 intKalue Q Integer.parseIntaraeter4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob errorCode X *rrorCode.M""BG"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od catc% Bumber$ormat#Eception e4 _`Ob error/araeter X araeter errorCode X *rrorCode."B(L"-"BT*G*R t%ro? ne? (rgs*>cetion4 _`Od _`Od
ublic cetion cetion _`Ob (rgs args X ne? (rgs>kk, ne? tringU _`Ob1>,V2.W_`Od4 assertTrueargs.isalid44 assert*@uals, args.cardinalit544 assertTrueargs.%asm>h44 assert*@ualsV2.W, args.get-oublem>h4, .004 _`Od Liiaos el código de an=lisis de es@ueas 5 a3adios la detección kk ara el tio de arguento double. ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s /arse*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# eleentTail.lengt/R QQ <4 ars%alers.uteleent"d, ne? )oolean(rguentMars%aler44 else i# eleentTail.e9ualsR_U`4 ars%alers.uteleent"d, ne? tring(rguentMars%aler44 else i# eleentTail.e9ualsR_`4 ars%alers.uteleent"d, ne? "nteger(rguentMars%aler44 else if Relement3ail.e9ualsR_` mars/alers.putRelementId* new 2oubleArgumentMars/alerRT
else t%ro? ne? /arse*>cetiontring.#orat (rguent: c %as in6alid #orat: s., eleent"d, eleentTail4, 04 _`Od eguidaente, creaos la clase -ouble(rguentMars%aler. pri+ate class 2oubleArgumentMars/aler implements ArgumentMars/aler ]^=b pri+ate double doubleKalue Q
]^=d catc/ RBoSuc/#lement#Eception e ]^=b errorCode Q #rrorCode. MISSIB.2O8(!#T t/row new Args#EceptionRT ]^=d catc/ RBumber$ormat#Eception e ]^=b errorParameter Q parameterT errorCode Q #rrorCode.IBKA!I2Z2O8(!#T t/row new Args#EceptionRT ]^=d ]^=d public Ob)ect getR ]^=b return doubleKalueT ]^=d ]^=d
*sto nos obliga a a3adir un nue6o código de error *rrorCode4. ri6ate enu *rrorCode _`Ob <$, M""BGTR"BG, M""BG"BT*G*R, "B(L"-"BT*G*R, B*+/*CT*-(RGM*BT, MISSIBZ2O8(!#* IBKA!I2Z2O8(!#_`Od E necesitaos una #unción get-ouble. public double get2oubleRc/ar arg ]^=b Args.ArgumentMars/aler am Q mars/alers.getRargT tr- ]^=b return am Q null ' < H R2ouble am.getRT ]^=d catc/ R#Eception e ]^=b return <.cetion _`Ob (rgs args X ne? (rgs>kk, ne? tringU _`Ob1>, ort5 t?o_`Od4 assertalseargs.isalid44 assert*@uals0, args.cardinalit544 assertalseargs.%asm>h44 assert*@uals0, args.get"ntm>h44 assert*@uals(rguent 1> e>ects a double but ?as mort5 t?oh., args.errorMessage44 _`Od 111 ublic tring errorMessage4 t%ro?s *>cetion _`Ob s?itc% errorCode4 _`Ob case <$: t%ro? ne? *>cetionT"LT: %ould not get %ere.4
case B*+/*CT*- (RGM*BT: return une>ected(rguentMessage4 case M""BGTR"BG: return tring.#oratCould not #in string araeter #or 1c., error(rguent"d4 case "B(L"-"BT*G*R: return tring.#orat(rguent 1c e>ects an integer but ?as msh., error(rguent"d, error/araeter4 case M""BG"BT*G*R: return tring.#oratCould not #ind integer araeter #or 1c., error(rguent"d4 case IBKA!I2Z2O8(!#H return String.formatR_Argument Fc eEpects a double but was s.`* errorArgumentId* errorParameterT case MISSIBZ2O8(!#H return String.formatR_Could not find double parameter for Fc`* errorArgumentIdT
_`Od return _`Od E las ruebas son satis#actorias. La siguiente rueba garanti!a @ue se detecte correctaente la ausencia de un arguento double. public +oid testMissing2oubleR t/rows #Eception ]^=b Args args Q new ArgsR_E`* new String;>]^=bFE]^=dT assert$alse Rargs.isKalidRT assert#9ualsR<* args.cardinalit-RT assert$alseRargs./asRET assert#9ualsR<.<* args.get2oubleRE* <.<T assert#9ualsR_Could not find double parameter for FE.`* args.errorMessageRT ]^=d *s correcto. La incluios ara @ue el e8elo resulte =s coleto. *l código de e>ceciones no es atracti6o 5 no ertenece realente a la clase (rgs. Tabién generaos /arse*>cetion, @ue no nos ertenece. /or ello, cobinaos todas las e>ceciones en una ;nica clase (rgs*>cetion 5 la incluios en su roio ódulo. public class Args#Eception eEtends #Eception ]^=b pri+ate c/ar errorArgumentId Q ]<T pri+ate String errorParameter Q _3I!3`T pri+ate #rrorCode errorCode Q #rrorCode.O?T public Args#EceptionR ]^=b]^=d public Args#EceptionRString message ]^=b superRmessageT ]^=d public enum #rrorCode ]^=b O?* MISSIBZS34IB* MISSIBZIB3##4* IBKA!I2ZIB3##4* 8B#7P#C3#2ZA48M#B3* MISSIBZ2O8(!#* IBKA!I2Z2O8(!# ]^=d
]^=d Y ublic class (rgs _`Ob Y ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X T"LT ri6ate Args#Eception.*rrorCode errorCode X Args#Eception.*rrorCode.<$ ri6ate List]tring^ argsList ublic (rgstring sc%ea, tringU args4 t%ro?s Args#Eception _`Ob t%is.sc%ea X sc%ea argsList X (rra5s.asListargs4 6alid X arse4 _`Od ri6ate boolean arse4 t%ro?s (rgs*>cetion _`Ob i# sc%ea.lengt%4 XX 0 '' argsList.si!e 4 XX 04 return true arsec%ea4 tr5 _`Ob arse(rguents4 _`Od catc% Args#Eception e4 _`Ob _`Od return 6alid _`Od ri6ate boolean arsec%ea4 t%ro?s Args#Eception _`Ob Y _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s Args#Eception _`Ob Y else t%ro? ne? Args#Eception tring.#orat(rguent: c %as in6alid #orat: s., eleent"d, eleentTail44 _`Od ri6ate 6oid 6alidatec%ea*leent"dc%ar eleent"d4 t%ro?s Args#Eception _`Ob i# C%aracter.isLettereleent"d44 _`Ob t%ro? ne? Args#Eception )ad c%aracter: Z eleent"d Z in (rgs #orat: Z sc%ea4 _`Od _`Od Y ri6ate 6oid arse*leentc%ar argC%ar4 t%ro?s Args#Eception _`Ob i# set(rguentargC%ar44 argsound.addargC%ar4 else _`Ob une>ected(rguents.addargC%ar4 errorCode X Args#Eception.*rrorCode.B*+/*CT*-(RGM*BT
6alid X #alse _`Od _`Od Y ri6ate class tring(rguentMars%aler ileents (rguentMars%aler _`Ob ri6ate tring stringalue X ublic 6oid set"terator]tring^ current(rguent4 t%ro?s (rgs*>cetion _`Ob tr5 _`Ob stringalue X current(rguent.ne>t4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob errorCode X Args#Eception.*rrorCode.M""BGTR"BG t%ro? ne? (rgs*>cetion4 _`Od _`Od ublic t4 intalue X "nteger.arse"ntaraeter4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob errorCode X (rgs*>cetion.*rrorCode.M""BG"BT*G*R t%ro? ne? Args#Eception4 _`Od catc% Buberorat*>cetion e4 _`Ob error/araeter X araeter errorCode X Args#Eception.*rrorCode."B(L"-"BT*G*R t%ro? ne? Args#Eception4 _`Od _`Od ublic cetion _`Ob tring araeter X null tr5 _`Ob araeter X current(rguent.ne>t4 doublealue X -ouble.arse-oublearaeter4 _`Od catc% Bouc%*leent*>cetion e4 _`Ob errorCode X Args#Eception.*rrorCode.M""BG-<)L*
t%ro? ne? (rgs*>cetion4 _`Od catc% Buberorat*>cetion e4 _`Ob error/araeter X araeter errorCode X Args#Eception.*rrorCode."B(L"--<)L* t%ro? ne? (rgs*>cetion4 _`Od _`Od ublic cetion. (l desla!ar (rgs*>cetion a un ódulo roio, odeos a3adir a dic%o ódulo gran arte del código de error 5 e>traerlo del ódulo (rgs. *s una osición natural 5 e6idente ara incluir todo el código 5 nos eritir= liiar osteriorente el ódulo (rgs. Ea %eos searado el código de e>ceciones 5 de error del ódulo (rgs 6éanse los listados del V.W al V.N4. /ara ello reali!aos una serie de W0 asos ínios 5 las ruebas #ueron satis#actorias entre todos ellos. !istado FG
(rgsTest.8a6a. ac&age co.ob8ectentor.utilities.args iort 8unit.#rae?or&.TestCase ublic class (rgsTest e>tends TestCase _`Ob ublic 6oid testCreate7it%Boc%eacetion _`Ob (rgs args X ne? (rgs, ne? tring0U4 assert*@uals0, args.cardinalit544 _`Od ublic 6oid test7it%Boc%ea)ut7it%cetion _`Ob tr5 _`Ob ne? (rgs, ne? tringU_`Ob1>_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode.B*+/*CT*-(RGM*BT, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44 _`Od _`Od ublic 6oid test7it%Boc%ea)ut7it%Multile(rguents4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs, ne? tringU_`Ob1>, 15_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode.B*+/*CT*-(RGM*BT, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44
_`Od _`Od ublic 6oid testBonLetterc%ea4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs, ne? tringU_`Ob_`Od4 #ail(rgs constructor s%ould %a6e t%ro?n e>cetion4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode."B(L"-(RGM*BTB(M*, e.get*rrorCode44 assert*@ualsmh, e.get*rror(rguent"d44 _`Od _`Od ublic 6oid test"n6alid(rguentorat4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs#p, ne? tringU_`Ob_`Od4 #ail(rgs constructor s%ould %a6e t%ro?s e>cetion4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode."B(L"-cetion.*rrorCode."B(L"- cetion _`Ob (rgs args X ne? (rgs>, ne? tring U_`Ob1>_`Od4 assert*@uals , args.cardinalit544 assert*@ualstrue, args.get)ooleanm>h44 _`Od ublic 6oid testiletring/resent4 t%ro?s *>cetion _`Ob (rgs args X ne? (rgs>, ne? tringU_`Ob1>, ara_`Od4 assert*@uals, args.cardinalit544 assertTrueargs.%asm>h44 assert*@ualsara, args.gettringm>h44 _`Od ublic 6oid testMissingtring(rguent4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs>, ne? tringU_`Ob1>_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals (rgs*>cetion.*rrorCode.M""BGTR"BG, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44 _`Od _`Od ublic 6oid testaces"norat4 t%ro?s *>cetion _`Ob (rgs args X ne? (rgs>, 5, ne? tringU_`Ob1>5_`Od4 assert*@uals2, args.cardinalit544 assertTrueargs.%asm>h44 assertTrueargs.%asm5h44 _`Od
ublic 6oid testile"nt/resent4 t%ro?s *>cetion _`Ob (rgs args X ne? (rgs>k, ne? tringU_`Ob1>, V2_`Od4 assert*@uals, args.cardinalit544 assertTrueargs.%asm>h44 assert*@ualsV2, args.get"ntm>h44 _`Od ublic 6oid test"n6alid"nteger4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs>k, ne? tringU _`Ob1>, ort5 t?o_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode."B(L"-"BT*G*R, assert*@uals(rgs*>cetion.*rrorCode."B(L"- "BT*G*R, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44 assert*@ualsort5 t?o, e.get*rror/araeter44 _`Od _`Od ublic 6oid testMissing"nteger4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs>k, ne? tringU_`Ob1>_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode.M""BG"BT*G*R, assert*@uals(rgs*>cetion.*rrorCode.M"" BG"BT*G*R, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44 _`Od _`Od ublic 6oid testile-ouble/resent4 t%ro?s *>cetion _`Ob (rgs args X ne? (rgs>kk, ne? tringU1>, V2.W_`Od4 assert*@uals, args.cardinalit544 assertTrueargs.%asm>h44 assert*@ualsV2.W, args.get-oublem>h4, .004 _`Od ublic 6oid test"n6alid-ouble4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs>kk, ne? tring U_`Ob1>, ort5 t?o_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode."B(L"--<)L*, assert*@uals(rgs*>cetion.*rrorCode."B(L"- -<)L*, e.get*rrorCode44 assert*@ualsm>h, e.get*rror(rguent"d44 assert*@ualsort5 t?o, e.get*rror/araeter44 _`Od _`Od ublic 6oid testMissing-ouble4 t%ro?s *>cetion _`Ob tr5 _`Ob ne? (rgs>kk, ne? tringU_`Ob1>_`Od4 #ail4 _`Od catc% (rgs*>cetion e4 _`Ob assert*@uals(rgs*>cetion.*rrorCode.M""BG-<)L*, assert*@uals(rgs*>cetion.*rrorCode.M"" BG-<)L*, e.get*rrorCode44
assert*@ualsm>h, e.get*rror(rguent"d44 _`Od _`Od _`Od !istado F
(rgs*>cetionTest.8a6a. ublic class (rgs*>cetionTest e>tends TestCase _`Ob ublic 6oid testne>ectedMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode.B*+/*CT*-(RGM*BT, m>h, null4 assert*@uals(rguent 1> une>ected., e.errorMessage44 _`Od ublic 6oid testMissingtringMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode.M""BGTR"BG, m>h, null4 assert*@ualsCould not #ind string araeter #or >., e.errorMessage44 _`Od ublic 6oid test"n6alid"ntegerMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode."B(L"- (rgs*>cetion(rgs*>cetion.*rrorCode."B(L"-"BT*G*R, "BT*G*R, m>h, ort5 t?o4 assert*@uals(rguent > e>ects an integer but ?as mort5 t?oh., e.errorMessage44 _`Od ublic 6oid testMissing"ntegerMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode.M"" (rgs*>cetion(rgs*>cetion.*rrorCode.M""BG"BT*G*R, BG"BT*G*R, m>h, null4 assert*@ualsCould not #ind integer araeter #or 1>., e.errorMessage44 _`Od ublic 6oid test"n6alid-oubleMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode."B(L"--<)L*, m>h, ort5 t?o4 assert*@uals(rguent 1> e>ects a double but ?as mort5 t?oh., e.errorMessage44 _`Od ublic 6oid testMissing-oubleMessage4 t%ro?s *>cetion _`Ob (rgs*>cetion e X ne? (rgs*>cetion(rgs*>cetion.*rrorCode.M""BG-<)L*, m>h, null4 assert*@ualsCould not #ind double araeter #or 1>., e.errorMessage44 _`Od _`Od !istado F
(rgs*>cetion.8a6a. ublic class (rgs*>cetion e>tends *>cetion _`Ob ri6ate c%ar error(rguent"d X m_0h ri6ate tring error/araeter X T"LT ri6ate *rrorCode errorCode X *rrorCode.<$ ublic (rgs*>cetion4 _`Ob_`Od ublic (rgs*>cetiontring essage4 _`Obsueressage4_`Od ublic (rgs*>cetion*rrorCode errorCode4 _`Ob t%is.errorCode X errorCode _`Od ublic (rgs*>cetion*rrorCode errorCode, tring error/araeter4 _`Ob t%is.errorCode X errorCode t%is.error/araeter X error/araeter _`Od ublic (rgs*>cetion*rrorCode errorCode, c%ar error(rguent"d, tring error/araeter4 _`Ob t%is.errorCode X errorCode t%is.error/araeter X error/araeter t%is.error(rguent"d X error(rguent"d _`Od ublic c%ar get*rror(rguent"d4 _`Ob return error(rguent"d _`Od ublic 6oid set*rror(rguent"dc%ar error(rguent"d4 _`Ob t%is.error(rguent"d X error(rguent"d _`Od ublic tring get*rror/araeter4 _`Ob return error/araeter _`Od ublic 6oid set*rror/araetertring error/araeter4 _`Ob t%is.error/araeter X error/araeter _`Od ublic *rrorCode get*rrorCode4 _`Ob return errorCode _`Od ublic 6oid set*rrorCode*rrorCode errorCode4 _`Ob t%is.errorCode X errorCode _`Od ublic tring errorMessage4 t%ro?s *>cetion _`Ob s?itc% errorCode4 _`Ob case <$: t%ro? ne? *>cetionT"LT: %ould not get %ere.4 case B*+/*CT*-(RGM*BT: return tring.#orat(rguent 1c une>ected., error(rguent"d4 case M""BGTR"BG: return tring.#oratCould not #ind string araeter #or 1c.,
error(rguent"d4 case "B(L"-"BT*G*R: return tring.#orat(rguent 1c e>ects an integer but ?as msh., error(rguent"d, error/araeter4 case M""BG"BT*G*R: return tring.#oratCould not #ind integer araeter #or 1c., error(rguent"d4 case "B(L"--<)L*: return tring.#orat(rguent 1c e>ects a double but ?as msh., error(rguent"d, error/araeter4 case M""BG-<)L*: return tring.#oratCould not #ind double araeter #or 1c., error(rguent"d4 _`Od return _`Od ublic enu *rrorCode <$, "B(L"-
(rgs.8a6a. ublic class (rgs _`Ob ri6ate tring sc%ea ri6ate Ma]C%aracter, (rguentMars%aler^ ars%alers X ne? as%Ma]C%aracter, (rguentMars%aler^4 ri6ate et]C%aracter^ argsound X ne? as%et]C%aracter^4 ri6ate "terator]tring^ current(rguent ri6ate List]tring^ argsList ublic (rgstring sc%ea, tringU args4 t%ro?s (rgs*>cetion _`Ob t%is.sc%ea X sc%ea argsList X (rra5s.asListargs4 arse4 _`Od ri6ate 6oid arse4 t%ro?s (rgs*>cetion _`Ob arsec%ea4 arse(rguents4 _`Od ri6ate boolean arsec%ea4 t%ro?s (rgs*>cetion _`Ob #or tring eleent : sc%ea.slit,44 _`Ob i# eleent.lengt%4 ^ 04 _`Ob arsec%ea*leenteleent.tri44 _`Od
_`Od return true _`Od ri6ate 6oid arsec%ea*leenttring eleent4 t%ro?s (rgs*>cetion _`Ob c%ar eleent"d X eleent.c%ar(t04 tring eleentTail X eleent.substring4 6alidatec%ea*leent"deleent"d4 i# eleentTail.lengt%4 XX 04 ars%alers.uteleent"d, ne? )oolean(rguentMars%aler44 else i# eleentTail.e@uals44 ars%alers.uteleent"d, ne? tring(rguentMars%aler44 else i# eleentTail.e@ualsk44 ars%alers.uteleent"d, ne? "nteger(rguentMars%aler44 else i# eleentTail.e@ualskk44 ars%alers.uteleent"d, ne? -ouble(rguentMars%aler44 else t%ro? ne? (rgs*>cetion(rgs*>cetion.*rrorCode."B( (rgs*>cetion(rgs*>cetion.*rrorCode."B(L"-cetion _`Ob i# C%aracter.isLettereleent"d44 _`Ob t%ro? ne? (rgs*>cetion(rgs*>cetion.*rrorCode."B(L"-(RGM*BTB(M*, eleent"d, null4 _`Od _`Od ri6ate 6oid arse(rguents4 t%ro?s (rgs*>cetion _`Ob #or current(rguent X argsList.iterator4 current(rguent.%asBe>t44 _`Ob tring arg X current(rguent.ne>t4 arse(rguentarg4 _`Od _`Od ri6ate 6oid arse(rguenttring arg4 t%ro?s (rgs*>cetion _`Ob i# arg.starts7it%144 arse*leentsarg4 _`Od ri6ate 6oid arse*leentstring arg4 t%ro?s (rgs*>cetion _`Ob #or int i X i ] arg.lengt%4 iZZ4 arse*leentarg.c%ar(ti44 _`Od ri6ate 6oid arse*leentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob i# set(rguentargC%ar44 argsound.addargC%ar4 else _`Ob t%ro? ne? (rgs*>cetion(rgs*>cetion.*rrorCode.B*+/*CT*-(RGM*BT, argC%ar, null4
_`Od _`Od ri6ate boolean set(rguentc%ar argC%ar4 t%ro?s (rgs*>cetion _`Ob (rguentMars%aler X ars%alers.getargC%ar4 i# XX null4 return #alse tr5 _`Ob .setcurrent(rguent4 return true _`Od catc% (rgs*>cetion e4 _`Ob e.set*rror(rguent"dargC%ar4 t%ro? e _`Od _`Od ublic int cardinalit54 _`Ob return argsound.si!e4 _`Od ublic tring usage4 _`Ob i# sc%ea.lengt%4 ^ 04 return 1 Z sc%ea Z U else return _`Od ublic boolean get)ooleanc%ar arg4 _`Ob (rguentMars%aler a X ars%alers.getarg4 boolean b X #alse tr5 _`Ob b X a X null '' )oolean4 a.get4 _`Od catc% ClassCast*>cetion e4 _`Ob b X #alse _`Od return b _`Od ublic tring gettringc%ar arg4 _`Ob (rguentMars%aler a X ars%alers.getarg4 tr5 _`Ob return a XX null I : tring4 a.get4 _`Od catc% ClassCast*>cetion e4 _`Ob return _`Od _`Od ublic int get"ntc%ar arg4 _`Ob (rguentMars%aler a X ars%alers.getarg4 tr5 _`Ob return a XX null I 0 : "nteger4 a.get4 _`Od catc% *>cetion e4 _`Ob return 0
_`Od _`Od ublic double get-oublec%ar arg4 _`Ob (rguentMars%aler a X ars%alers.getarg4 tr5 _`Ob return a XX null I 0 : -ouble4 a.get4 _`Od catc% *>cetion e4 _`Ob return 0.0 _`Od _`Od ublic boolean %asc%ar arg4 _`Ob return argsound.containsarg4 _`Od _`Od La a5oría de los cabios reali!ados en la clase (rgs %an sido eliinaciones. Gran arte del código se e>tra8o de (rgs 5 se a3adió a 3adió a (rgs*>cetion. /er#ecto. Tabién cabiaos todos los eleentos (rguentMars%aller a sus roios arc%i6os. Me8or toda6ía. *l dise3o de software correcto se basa gran arte en las articiones, en crear !onas adecuadas ara incluir distintos tios de código. *sta searación %ace @ue el código sea =s #=cil de entender 5 antener. *secialente interesante es el étodo errorMessage de (rgs*>cetion. "ncule claraente el R/ al incluir el #orato de ensa8es de error en (rgs. (rgs debe centrarse en el rocesaiento de arguentos, no en el #orato de los ensa8es de error. in ebargo, Hrealente tiene sentido incluir el código de #orato de ensa8es de error en (rgs*>cetionI rancaente es un coroiso. Los usuarios @ue no deseen los ensa8es de error roorcionados or (rgs*>cetion (rgs*>c etion tendr=n @ue crear los su5os roios, r oios, ero la utilidad de ensa8es de error 5a rearados es e6idente. Ea debería %aberse dado cuenta de la distancia recorrida con resecto a la solución ostrada al inicio del caítulo. Las trans#oraciones #inales uede e>ainarlas or su cuenta.
Conclusión Bo basta con @ue el código #uncione. *l código @ue #unciona suele ser incorrecto. Los rograadores @ue se con#oran con código #uncional no se coortan de #ora ro#esional. /uede @ue tean @ue no tienen tieo ara e8orar la estructura 5 el dise3o del código, ero discreo. Bo %a5 nada @ue a#ecte =s negati6aente a un ro5ecto de desarrollo @ue el código incorrecto. Los la!os incorrectos se ueden re%acer 5 los re@uisitos e@ui6ocados se ueden 6ol6er a de#inir. La din=ica incorrecta de un e@uio se uede rearar ero el código có digo incorrecto se corroe 5 se con6ierte co n6ierte en una carga @ue arrastra al e@uio coleto. e 6isto e@uios doinados or el desastre @ue %an generado 5 @ue %an doinado su destino. *6identeente, el código incorrecto se uede liiar ero resulta u5 costoso. Cuando el código se corroe los ódulos se insin;an unos a otros 5 generan ultitud de deendencias ocultas 5 entrela!adas. La locali!ación 5 di6isión de deendencias antiguas es
una tarea larga 5 colicada. /or otra arte, resulta relati6aente sencillo antener código liio. i coete un error en un ódulo, es =s #=cil liiarlo directaente. Me8or toda6ía, si coetió un error %ace cinco inutos, es u5 #=cil liiarlo a%ora. /or tanto, la solución consiste en antener el código liio 5 sencillo siere @ue se ueda 5 no de8ar @ue llegue a corroerse.
Aspectos internos de J8nit
Jnit es una de las estructuras de Ja6a =s conocidas. -e conceción sencilla, de#inición recisa 5 docuentación elegante. HE su códigoI *n este caítulo anali!areos un e8elo e>traído de la estructura Jnit.
!a estructura J8nit Jnit %a tenido uc%os autores, coen!ando or $ent )ec& 5 *ric Gaa en un 6uelo a (tlanta. $ent @uería arender Ja6a 5 *ric @uería saber =s sobre la estructura de ruebas alltal& de $ent. Ha5 algo =s natural @ue dos #an=ticos enciendan sus ort=tiles 5 eiecen a escribir códigoI9VU Tras tres %oras de traba8o de altura, %abían
creado los #undaentos de Jnit. *l ódulo @ue anali!areos es un inteligente #ragento de código @ue erite identi#icar errores de coaración de cadenas. *l nobre del ódulo es CoarisonCoactor. -adas dos cadenas di#erentes, coo ()C-* 5 ()+-*, uestra la di#erencia entre abas generando una cadena coo ]Y)+U-Y^. /odríaos e>licarlo =s, ero los casos de rueba son e8ores. í8ese en el Listado 1 ara corender los re@uisitos de este ódulo. (nalice la estructura de las ruebas. H/odrían ser =s siles o =s e6identesI !istado F
CoarisonCoactorTest.8a6a. ac&age 8unit.tests.#rae?or& iort 8unit.#rae?or&.CoarisonCoactor iort 8unit.#rae?or&.TestCase ublic class CoarisonCoactorTest e>tends TestCase _`Ob ublic 6oid testMessage4 _`Ob tring #ailureX ne? CoarisonCoactor0, b, c4.coacta4 assertTruea e>ected:]bU^ but ?as:]cU^.e@uals#ailure44 _`Od ublic 6oid testtartae4 _`Ob tring #ailureX ne? CoarisonCoactor, ba, bc4.coactnull4 assert*@ualse>ected:]baU^ but ?as:]bcU^, #ailure4 _`Od ublic 6oid test*ndae4 _`Ob tring #ailureX ne? CoarisonCoactor, ab, cb4.coactnull4 assert*@ualse>ected:]aUb^ but ?as:]cUb^, #ailure4 _`Od ublic 6oid testae4 _`Ob tring #ailureX ne? CoarisonCoactor, ab, ab4.coactnull4 assert*@ualse>ected:]ab^ but ?as:]ab^, #ailure4 _`Od ublic 6oid testBoConte>ttart(nd*ndae4 _`Ob tring #ailureX ne? CoarisonCoactor0, abc, adc4.coactnull4 assert*@ualse>ected:]YbUY^ but ?as:]YdUY^, #ailure4 _`Od ublic 6oid testtart(nd*ndConte>t4 _`Ob tring #ailureX ne? CoarisonCoactor, abc, adc4.coactnull4 assert*@ualse>ected:]abUc^ but ?as:]adUc^, #ailure4 _`Od ublic 6oid testtart(nd*ndConte>t7it%*llises4 _`Ob tring #ailureX ne? CoarisonCoactor, abcde, ab#de4.coactnull4 assert*@ualse>ected:]YbcUdY^ but ?as:]Yb#UdY^, #ailure4 _`Od ublic 6oid testCoarison*rrortartaeColete4 _`Ob tring #ailureX ne? CoarisonCoactor2, ab, abc4.coactnull4 assert*@ualse>ected:]abU^ but ?as:]abcU^, #ailure4
_`Od ublic 6oid testCoarison*rror*ndaeColete4 _`Ob tring #ailureX ne? CoarisonCoactor0, bc, abc4.coactnull4 assert*@ualse>ected:]UY^ but ?as:]aUY^, #ailure4 _`Od ublic 6oid testCoarison*rror*ndaeColeteConte>t4 _`Ob tring #ailureX ne? CoarisonCoactor2, bc, abc4.coactnull4 assert*@ualse>ected:]Ubc^ but ?as:]aUbc^, #ailure4 _`Od ublic 6oid testCoarison*rror<6erlaingMatc%es4 _`Ob tring #ailureX ne? CoarisonCoactor0, abc, abbc4.coactnull4 assert*@ualse>ected:]YUY^ but ?as:]YbUY^, #ailure4 _`Od ublic 6oid testCoarison*rror<6erlaingMatc%esConte>t4 _`Ob tring #ailureX ne? CoarisonCoactor2, abc, abbc4.coactnull4 assert*@ualse>ected:]abUc^ but ?as:]abbUc^, #ailure4 _`Od ublic 6oid testCoarison*rror<6erlaingMatc%es24 _`Ob tring #ailureX ne? CoarisonCoactor0, abcdde, abcde4.coactnull4 assert*@ualse>ected:]YdUY^ but ?as:]YUY^, #ailure4 _`Od ublic 6oid testCoarison*rror<6erlaingMatc%es2Conte>t4 _`Ob tring #ailureX ne? CoarisonCoactor2, abcdde, abcde4.coactnull4 assert*@ualse>ected:]YcddUe^ but ?as:]YcdUe^, #ailure4 _`Od ublic 6oid testCoarison*rror7it%(ctualBull4 _`Ob tring #ailureX ne? CoarisonCoactor0, a, null4.coactnull4 assert*@ualse>ected:]a^ but ?as:]null^, #ailure4 _`Od ublic 6oid testCoarison*rror7it%(ctualBullConte>t4 _`Ob tring #ailureX ne? CoarisonCoactor2, a, null4.coactnull4 assert*@ualse>ected:]a^ but ?as:]null^, #ailure4 _`Od ublic 6oid testCoarison*rror7it%*>ectedBull4 _`Ob tring #ailureX ne? CoarisonCoactor0, null, a4.coactnull4 assert*@ualse>ected:]null^ but ?as:]a^, #ailure4 _`Od ublic 6oid testCoarison*rror7it%*>ectedBullConte>t4 _`Ob tring #ailureX ne? CoarisonCoactor2, null, a4.coactnull4 assert*@ualse>ected:]null^ but ?as:]a^, #ailure4 _`Od ublic 6oid test)ugN099O24 _`Ob tring #ailureX ne? CoarisonCoactor0, '/00, 04.coactnull4 assert*@ualse>ected:]'/0U0^ but ?as:]U0^, #ailure4 _`Od
_`Od Realicé un an=lisis de alcance de código en CoarisonCoactor con estas ruebas. *l código se cubre en un 00 or 00. Cada línea, cada instrucción i# 5 cada bucle #or se e8ecuta con las ruebas. -e este odo sé @ue el código #unciona 5 sus autores e erecen el a5or de los resetos. *l código CoarisonCoactor se reroduce en el Listado 12. *>aínelo. Creo @ue lo encontrar= bien distribuido, ra!onableente e>resi6o 5 estructuralente sencillo. Cuando terine, lo diseccionareos. !istado F
CoarisonCoactor.8a6a tLengt% ri6ate tring #*>ected ri6ate tring #(ctual ri6ate int #/re#i> ri6ate int #u##i> ublic CoarisonCoactorint conte>tLengt%, tring e>ected, tring actual4 _`Ob #Conte>tLengt% X conte>tLengt% #*>ected X e>ected #(ctual X actual _`Od ublic tring coacttring essage4 _`Ob i# #*>ected XX null #(ctual XX null aretrings*@ual44 return (ssert.#oratessage, #*>ected, #(ctual4 #indCoon/re#i>4 #indCoonu##i>4 tring e>ected X coacttring#*>ected4 tring actual X coacttring#(ctual4 return (ssert.#oratessage, e>ected, actual4 _`Od ri6ate tring coacttringtring source4 _`Ob tring result X -*LT(T(RT Z source.substring#/re#i>, source.lengt%4 1 #u##i> Z 4 Z -*LT(*B- i# #/re#i> ^ 04 result X couteCoon/re#i>4 Z result i# #u##i> ^ 04 result X result Z couteCoonu##i>4 return result _`Od
ri6ate 6oid #indCoon/re#i>4 _`Ob #/re#i> X 0 int end X Mat%.in#*>ected.lengt%4, #(ctual.lengt%44 #or #/re#i> ] end #/re#i>ZZ4 _`Ob i# #*>ected.c%ar(t#/re#i>4 X #(ctual.c%ar(t#/re#i>44 brea& _`Od _`Od ri6ate 6oid #indCoonu##i>4 _`Ob int e>ectedu##i> X #*>ected.lengt%4 1 int actualu##i> X #(ctual.lengt%4 1 #or actualu##i> ^X #/re#i> '' e>ectedu##i> ^X #/re#i> actualu##i>11, e>ectedu##i>114 _`Ob i# #*>ected.c%ar(te>ectedu##i>4 X #(ctual.c%ar(tactualu##i>44 brea& _`Od #u##i> X #*>ected.lengt%4 1 e>ectedu##i> _`Od ri6ate tring couteCoon/re#i>4 _`Ob return #/re#i> ^ #Conte>tLengt% I *LL"/" : 4 Z #*>ected.substringMat%.a>0, #/re#i> 1 #Conte>tLengt%4, #/re#i>4 _`Od ri6ate tring couteCoonu##i>4 _`Ob int end X Mat%.in#*>ected.lengt%4 1 #u##i> Z Z #Conte>tLengt%, #*>ected.lengt%44 return #*>ected.substring#*>ected.lengt%4 1 #u##i> Z , end4 Z #*>ected.lengt%4 1 #u##i> Z ] #*>ected.lengt%4 1 #Conte>tLengt% I *LL"/" : 4 _`Od ri6ate boolean aretrings*@ual4 _`Ob return #*>ected.e@uals#(ctual4 _`Od _`Od /uede @ue tenga 6arias @ue8as sobre el ódulo. "nclu5e e>resiones e>tensas 5 e>tra3os eleentos Z. /ero en general, est= bastante bien. -esués de todo, odría %aber sido coo el Listado 1W. !istado .G CoarisonCoator.8a6a de#actori!ado4 ac&age 8unit.#rae?or& ublic class CoarisonCoactor _`Ob ri6ate int ct>t ri6ate tring s ri6ate tring s2 ri6ate int #>
ri6ate int s#> ublic CoarisonCoactorint ct>t, tring s, tring s24 _`Ob t%is.ct>t X ct>t t%is.s X s t%is.s2 X s2 _`Od ublic tring coacttring sg4 _`Ob i# s XX null s2 XX null s.e@ualss244 return (ssert.#oratsg, s, s24 #> X 0 #or #> ] Mat%.ins.lengt%4, s2.lengt%44 #>ZZ4 _`Ob i# s.c%ar(t#>4 X s2.c%ar(t#>44 brea& _`Od int s#> X s.lengt%4 1 int s#>2 X s2.lengt%4 1 #or s#>2 ^X #> '' s#> ^X #> s#>211, s#>114 _`Ob i# s.c%ar(ts#>4 X s2.c%ar(ts#>244 brea& _`Od s#> X s.lengt%4 1 s#> tring c X coacttrings4 tring c2 X coacttrings24 return (ssert.#oratsg, c, c24 _`Od ri6ate tring coacttringtring s4 _`Ob tring result X Z s.substring#>, s.lengt%4 1 s#> Z 4 Z U i# #> ^ 04 result X #> ^ ct>t I Y : 4 Z s.substringMat%.a>0, #> 1 ct>t4, #>4 Z result i# s#> ^ 04 _`Ob int end X Mat%.ins.lengt%4 1 s#> Z Z ct>t, s.lengt%44 result X result Z s.substrings.lengt%4 1 s#> Z , end4 Z s.lengt%4 1 s#> Z ] s.lengt%4 1 ct>t I Y : 44 _`Od return result _`Od _`Od (un@ue los autores %icieron un buen traba8o con este ódulo, la egla del =o. 9U Sco%t uestra @ue odrían %aberlo de8ado =s liio de lo @ue se encontró. HCóo odeos e8orar el código original del Listado 12I Lo riero @ue no necesitaos es el re#i8o # de las 6ariables iebro BNU. Los entornos en tornos actuales %acen @ue este tio de código de =bito sea redundante, or lo @ue eliinareos todas las #. ri6ate int conte>tLengt% ri6ate tring e>ected ri6ate tring actual
ri6ate int re#i> ri6ate int su##i> Tras ello, teneos una condicional sin encasular al inicio de la #unción coact G2AU. ublic tring coacttring essage4 _`Ob if ReEpected QQ null actual QQ null areStrings#9ualR return (ssert.#oratessage, e>ected, actual4 #indCoon/re#i>4 #indCoonu##i>4 tring e>ected X coacttringt%is.e>ected4 tring actual X coacttringt%is.actual4 return (ssert.#oratessage, e>ected, actual4 _`Od *s necesario encasular esta condicional ara @ue nuestra intención sea =s clara. /or tanto, e>traeos un étodo @ue la e>li@ue. ublic tring coacttring essage4 _`Ob i# s/ouldBotCompactR4 return (ssert.#oratessage, e>ected, actual4 #indCoon/re#i>4 #indCoonu##i>4 tring e>ected X coacttringt%is.e>ected4 tring actual X coacttringt%is.actual4 return (ssert.#oratessage, e>ected, actual4 _`Od pri+ate boolean s/ouldBotCompactR ]^=b return eEpected QQ null actual QQ null areStrings#9ualRT ]^=d *n la #unción coact, t%is.e>ected 5 t%is.actual no son deasiado rele6antes. ucede al cabiar el nobre de #*>ected or e>ected. H/or @ué esta #unción tiene 6ariables con los isos nobres @ue las 6ariables iebroI HBo reresentan cosas di#erentesIBVU. Los nobres deben ser e>clusi6os. tring compact#Epected X coacttringeEpected4 tring compactActual X coacttringactual4 Los negati6os son =s di#íciles de entender @ue los ositi6os G29U. /or ello, in6ertios esa instrucción i# ara cabiar el sentido de la condicional. ublic tring coacttring essage4 _`Ob i# can(eCompactedR4 _`Ob #indCoraon/re#i>4 #indCoonu##i>4 tring coact*>ected X coacttringe>ected4 tring coact(ctual X coacttringactual4 return (ssert.#oratessage, coact*>ected, coact(ctual4 _`Od else _`Ob return (ssert.#oratessage, e>ected, actual4 _`Od
_`Od ri6ate boolean can(eCompacted4 _`Ob return e>ected Q null XX actual Q null XX aretrings*@ual4 _`Od *l nobre de la #unción es e>tra3o BOU. (un@ue coacta las cadenas, uede @ue lo %aga si can)eCoacted de6uel6e #alse. (l asignar el nobre coact a esta #unción se oculta el e#ecto secundario de la corobación de errores. (de=s, la #unción de6uel6e un ensa8e con #orato, no sólo las cadenas coactadas. /or tanto, el nobre de la #unción debería ser #oratCoactedCoarison. -e esta #ora, se lee e8or 8unto al arguento de la #unción: ublic tring #oratCoactedCoarisontring essage4 _`Ob *l cuero de la instrucción i# es donde se reali!a la 6erdadera coactación de las cadenas. -ebeos e>traerlo coo étodo con el nobre coact*>ected(nd(ctual. in ebargo, @uereos @ue la #unción #oratCoactedCoarison realice todo el #orato. La #unción coactY sólo debe reali!ar la coactación GW0U, de odo @ue la di6idios de esta #ora: Y pri+ate String compact#EpectedT pri+ate String compactActualT Y ublic tring #oratCoactedCoarisontring essage4 _`Ob i# can)eCoacted44 _`Ob compact#EpectedAndActualRT return (ssert.#oratessage, coact*>ected, coact(ctual4 _`Od else _`Ob return (ssert.#oratessage, e>ected, actual4 _`Od _`Od ri6ate 6oid compact#EpectedAndActual4 _`Ob #indCoon/re#i>4 #indCoonu##i>4 coact*>ected X coacttringe>ected4 coact(ctual X coacttringactual4 _`Od /ara ello, %eos tenido @ue ascender coact*>ected 5 coact(ctual a 6ariables iebro. Bo e gusta la #ora en @ue las dos ;ltias líneas de la nue6a #unción de6uel6en 6ariables ero las dos rieras no lo %acen. Bo utili!an con6enciones co%erentes GU. -ebeos cabiar #indCoon/re#i> 5 #indCoonu##i> ara @ue de6uel6an los 6alores de re#i8o 5 su#i8o. ri6ate 6oid coact*>ected(nd(ctual4 _`Ob prefiEIndeE X #indCoon/re#i>4 suffiEIndeE X #indCoonu##i>4 coact*>ected X coacttringe>ected4 coact(ctual X coacttringactual4 _`Od
ri6ate int #indCoon/re#i>4 _`Ob int re#i>IndeE X 0 int end X Mat%.ine>ected.lengt%4, actual.lengt%44 #or re#i>IndeE ] end re#i>IndeEZZ4 _`Ob i# e>ected.c%ar(tre#i>IndeE4 X actual.c%ar(tre#i>IndeE44 brea& _`Od return prefiEIndeET
_`Od ri6ate int #indCoonu##i>4 _`Ob int e>ectedu##i> X e>ected.lengt%4 1 int actualu##i> X actual.lengt%4 1 #or actualu##i> ^X re#i>IndeE '' e>ectedu##i> ^X re#i>"nde> actualu##i>11, e>ectedu##i>114 _`Ob i# e>ected.c%ar(te>ectedu##i>4 X actual.c%ar(tactualu##i>44 brea& _`Od return e>ected.lengt%4 1 e>ectedu##i> _`Od Tabién debeos cabiar los nobres de las 6ariables iebro ara @ue sean =s reciosas B"U, 5a @ue en el #ondo son índices. (l e>ainar #indCoonu##i> 6eos una cone>ión teoral oculta GWU deende de @ue re#i>"nde> se calcule or #indCoon/re#i>. i estas dos #uncione se in6ocan de #ora desordenada, la sesión de deuración osterior seria colicada. /or ello, ara ostrar esta cobinación teoral, %areos @ue #indCoonu##i> acete re#i>"nde> coo arguento. ri6ate 6oid coact*>ected(nd(ctual4 _`Ob re#i>"nde> X #indCoon/re#i>4 su##i>"nde> X #indCoonu##i>prefiEIndeE4 coact*>ected X coacttringe>ected4 coact(ctual X coacttringactual4 _`Od ri6ate int #indCoonu##i>int prefiEIndeE4 _`Ob int e>ectedu##i> X e>ected.lengt%4 1 int actualu##i> X actual.lengt%4 1 #or actualu##i> ^X re#i>"nde> '' e>ectedu##i> ^X re#i>"nde> actualu##i>11, e>ectedu##i>114 _`Ob i# e>ected.c%ar(te>ectedu##i>4 X actual.c%ar(tactualu##i>44 brea& _`Od return e>ected.lengt%4 1 e>ectedu##i> _`Od Bo e con6ence del todo. *l %ec%o de asar re#i>"nde> coo arguento es un tanto arbitrario GW2U. /erite establecer el orden ero no e>lica la necesidad del iso.
ri6ate 6oid coact*>ected(nd(ctual4 _`Ob findCommonPrefiEAndSuffiERT
coact*>ected X coacttringe>ected4 coact(ctual X coacttringactual4 _`Od ri6ate +oid findCommonPrefiEAndSuffiE4 _`Ob findCommonPrefiERT
int e>ectedu##i> X e>ected.lengt%4 1 int actualu##i> X actual.lengt%4 1 #or actualu##i> ^X re#i>"nde> '' e>ectedu##i> ^X re#i>"nde> actualu##i>11, e>ectedu##i>11 4 _`Ob i# e>ected.c%ar(te>ectedu##i>4 X actual.c%ar(tactualu##i>44 brea& _`Od su##i>"nde> X e>ected.lengt%4 1 e>ectedu##i> _`Od ri6ate +oid #indCoon/re#i>4 _`Ob re#i>"nde> X 0 int end X Mat%.ine>ected.lengt%4, actual.lengt%44 #or re#i>"nde> ] end re#i>"nde>ZZ4 i# e>ected.c%ar(tre#i>"nde>4 X actual.c%ar(tre#i>"nde>44 brea& _`Od -e6ol6eos #indCoon/re#i> 5 #indCoonu##i> a su osición original, cabiaos el nobre de #indCoonu##i> or #indCoon/re#i>(ndu##i> 5 %aceos @ue in6o@ue #indCoon/re#i> antes de %acer nada =s. -e ese odo se establece la naturale!a teoral de abas #unciones de #ora =s e6idente @ue antes. (de=s, se uestra el ínio atracti6o de #indCoon/re#i>(ndu##i>, @ue liiareos a continuación: ri6ate 6oid #indCoon/re#i>(ndu##i>4 _`Ob #indCoon/re#i>4 int su##i>Lengt% X #or su##i><6erlas/re#i>su##i>Len su##i><6erlas/re#i>su##i>Lengt%4 gt%4 su##i>Lengt%ZZ4 _`Ob i# c%arro*nde>ected, su##i>Lengt%4 X c%arro*ndactual, su##i>Lengt%44 brea& _`Od su##i>"nde> X su##i>Lengt% _`Od ri6ate c%ar c%arro*ndtring s, int i4 _`Ob return s.c%ar(ts.lengt%41i4_`Od ri6ate boolean su##i><6erlas/re#i>int su##i>Lengt%4 _`Ob return actual.lengt%4 1 su##i>Lengt% ] re#i>Lengt%
e>ected.lengt%4 1 su##i>Lengt% ] re#i>Lengt% _`Od Muc%o e8or. Muestra @ue su##i>"nde> es en realidad la longitud del su#i8o 5 @ue su nobre no es correcto. Lo iso sucede con re#i>"nde>, aun@ue en ese caso índice 5 longitud son sinónios. "ncluso así, es =s co%erente usar lengt%. *l roblea es @ue la 6ariable su##i>"nde> no es de base cero, sino de base 5 no es una 6erdadera longitud. \ste es el oti6o de la abundancia de Z en couteCoonu##i> GWWJ. Lo corregios. *n el Listado 1V uede 6er el resultado. !istado F
CoarisonCoactor8a6a 6ersión interedia4. ublic class CoarisonCoactor _`Ob Y ri6ate int suffiE!engt/ Y ri6ate 6oid #indCoon/re#i>(ndu##i>4 _`Ob #indCoon/re#i>4 suffiE!engt/ Q <6erlas/re#i>su##i>Len su##i><6erlas/re#i>su##i>Lengt%4 gt%4 su##i>Lengt%ZZ4 _`Ob i# c%arro*nde>ected, su##i>Lengt%4 X c%arro*ndactual, su##i>Lengt%44 brea& _`Od _`Od ri6ate c%ar c%arro*ndtring s, int i4 _`Ob return s.c%ar(ts.lengt%4 1 i F 4 _`Od ri6ate boolean su##i><6erlas/re#i>int su##i>Lengt%4 _`Ob return actual.lengt%4 1 su##i>Lengt% VQ re#i>Lengt% e>ected.lengt%4 1 su##i>Lengt% VQ re#i>Lengt% _`Od Y ri6ate tring coacttringtring source4 _`Ob tring result X -*LT(T(RT Z source.substringre#i>Lengt%, source.lengt%4 1 suffiE!engt/4 Z -*LT(*B- i# re#i>Lengt% ^ 04 result X couteCoon/re#i>4 Z result i# suffiE!engt/ ^ 04 result X result Z couteCoonu##i>4 return result _`Od Y ri6ate tring couteCoonu##i>4 _`Ob int end X Mat%.ine>ected.lengt%4 1 suffiE!engt/ Z
conte>tLengt%, e>ected.lengt%4 4 return e>ected.substringe>ected.lengt%4 1 suffiE!engt/, end4 Z e>ected.lengt%4 1 suffiE!engt/ ] e>ected.lengt%4 1 conte>tLengt% I *LL"/" : 4 _`Od Cabiaos Z en couteCoonu##i> or un 1 en c%arro*nd, donde tiene sentido, 5 dos oeradores ]X su##i><6erlas/re#i>, totalente correctos. -e este odo odeos cabiar el nobre de su##i>"nde> su## i>"nde> or su##i>Lengt%, lo @ue e8ora considerableente la legibilidad del código. /ero %a5 un roblea. (l coen!ar a eliinar los Z, e #i8é en la siguiente línea de coactstring: i# su##i>Lengt% ^ 04 );s@uela en el Listado 1V. Coo a%ora su##i>Lengt% es una unidad enos @ue antes, debeos cabiar el oerador ^ or ^X. /ero eso no tiene sentido. (%ora sí. igni#ica @ue no tenía sentido antes 5 @ue seguraente #uera un error. )ueno, no del todo. Tras un an=lisis detallado, 6eos @ue a%ora la instrucción i# iide @ue se a3ada un su#i8o de longitud cero. (ntes de reali!ar el cabio, la instrucción i# no #uncionaba 5a @ue su##i>"nde> nunca odía ser enos de uno. *sto cuestiona abas instrucciones i# en coacttring. /arece coo si se udieran eliinar. /or ello, las coentaos 5 e8ecutaos las ruebas. atis#actorias. Reestructureos coacttring ara eliinar las instrucciones i# sobrantes 5 sili#icar la #unción G9U. ri6ate tring coacttringtring source4 _`Ob return couteCoon/re#i>4 Z -*LT(T(RT Z source.substringre#i>Lengt%, source.lengt%4 1 su##i>Lengt%4 Z -*LT(*B- Z couteCoonu##i>4 _`Od Muc%o e8or. (%ora 6eos @ue la #unción coacttring sileente cobina los #ragentos. /robableente lo odríaos liiar =s, en e@ue3as oeraciones, ero en lugar de desarrollar el resto de los cabios, ostrareos el resultado #inal en el Listado 1 . !istado . CoarisonCoactor.8a6a 6ersión de#initi6a4. ac&age 8unit.#rae?or& ublic class CoarisonCoactor _`Ob ri6ate static #inal tring *LL"/" X Y ri6ate static #inal tring -*LT(*B- X U ri6ate static #inal tring -*LT(T(RT X ri6ate int conte>tLengt% ri6ate tring e>ected
ri6ate tring actual ri6ate int re#i>Lengt% ri6ate int su##i>Lengt% ublic CoarisonCoactor int conte>tLengt%, tring e>ected, tring actual 4 _`Ob t%is.conte>tLengt% X conte>tLengt% t%is.e>ected X e>ected t%is.actual X actual _`Od ublic tring #oratCoactedCoarisontring essage4 _`Ob tring coact*>ected X e>ected tring coact(ctual X actual i# s%ould)eCoacted44 _`Ob #indCoon/re#i>(ndu##i>4 coact*>ected X coacte>ected4 coact(ctual X coactactual4 _`Od return (ssert.#oratessage, coact*>ected, coact(ctual4 _`Od ri6ate boolean s%ould)eCoacted4 _`Ob return s%ouldBot)eCoacted4 _`Od ri6ate boolean s%ouldBot)eCoacted4 _`Ob return e>ected XX null actual XX null e>ected.e@ualsactual4 _`Od ri6ate 6oid #indCoon/re#i>(ndu##i>4 _`Ob #indCoon/re#i>4 su##i>Lengt% X 0 #or su##i><6erlas/re#i>4 su##i>Lengt%ZZ4 _`Ob i# c%arro*nde>ected, su##i>Lengt%4 X c%arro*ndactual, su##i>Lengt%4 4 brea& _`Od _`Od ri6ate c%ar c%arro*ndtring s, int i4 _`Ob return s.c%ar(ts.lengt%4 1 i 1 4 _`Od ri6ate boolean su##i><6erlas/re#i>4 _`Ob return actual.lengt%4 1 su##i>Lengt% ]X re#i>Lengt% e>ected.lengt%4 1 su##i>Lengt% ]X re#i>Lengt% _`Od ri6ate 6oid #indCoon/re#i>4 _`Ob re#i>Lengt% X 0
int end X Mat%.ine>ected.lengt%4, actual.lengt%44 #or re#i>Lengt% ] end re#i>Lengt%ZZ4 i# e>ected.c%ar(tre#i>Lengt%4 X actual.c%ar(tre#i>Lengt%44 brea& _`Od ri6ate tring coacttring s4 _`Ob return ne? tring)uilder4 .aendstarting*llisis44 .aendstartingConte>t44 .aend-*LT(T(RT4 .aenddeltas44 .aend-*LT(*B-4 .aendendingConte>t44 .aendending*llisis44 .totring4 _`Od ri6ate tring starting*llisis4 _`Ob return re#i>Lengt% ^ conte>tLengt% I *LL"/" : _`Od ri6ate tring startingConte>t4 _`Ob int conte>ttart X Mat%.a>0, re#i>Lengt% 1 conte>tLengt%4 int conte>t*nd X re#i>Lengt% return e>ected.substringconte>ttart, conte>t*nd4 _`Od ri6ate tring deltatring s4 _`Ob int deltatart X re#i>Lengt% int delta*nd X s.lengt%4 1 su##i>Lengt% return s.substringdeltatart, delta*nd4 _`Od ri6ate tring endingConte>t4 _`Ob int conte>ttart X e>ected.lengt%4 1 su##i>Lengt% int conte>t*nd X Mat%.inconte>ttart Z conte>tLengt%, e>ected.lengt%44 return e>ected.substringconte>ttart, conte>t*nd4 _`Od ri6ate tring ending*llisis4 _`Ob return su##i>Lengt% ^ conte>tLengt% I *LL"/" : 4 _`Od _`Od )astante atracti6o. *l ódulo se seara en un gruo de #unciones de an=lisis 5 otro gruo de #unciones de síntesis. e ordenan toológicaente ara @ue la de#inición de cada #unción aare!ca donde realente se usa. /riero se uestran las #unciones de an=lisis 5 desués las de síntesis. i se #i8a atentaente, 6er= @ue %e in6ertido algunas de las decisiones adotadas inicialente. /or e8elo, %e a3adido algunos étodos e>traídos a #oratCoactedCoarison 5 %e odi#icado el sentido de la e>resión s%ouldBot)eCoacted. *s algo %abitual. ( enudo, un cabio de re#actori!ación lle6a a otro @ue a su 6e! lle6a a des%acer el riero. La re#actori!ación es un roceso iterati6o de
ensa5o 5 error, e ine6itableente con6erge en algo @ue consideraos digno de un ro#esional.
Conclusión eos culido la Regla del )o5 cout. eos de8ado este ódulo =s liio de cóo lo encontraos. Bo es @ue no estu6iera liio originalente, 5a @ue el traba8o de sus autores es e>celente, ero cual@uier ódulo se uede e8orar 5 es nuestra resonsabilidad de8ar el código =s liio de lo @ue lo encontraos.
L 4efactorización de Serial2ate
i 6isita %tt:QQ???.8#ree.orgQ8coonQinde>.%, encontrar= la biblioteca JCoon. *n su interior inclu5e el a@uete org.8#ree.date 5, dentro de éste, la clase erial-ate. aos a anali!ar esta clase. *l autor de erial-ate es -a6id Gilbert. -a6id es un rograador e>erientado 5 coetente. Coo 6ereos, uestra un ele6ado grado de ro#esionalidad 5 discilina en su código. *n lo @ue a éste resecta, se uede considerar de calidad. E 6o5 a deseda!arlo. Bo es un acto de alicia, ni taoco e creo e8or @ue -a6id 5 con el derec%o de 8u!gar su código. -e %ec%o, si le5era alg;n código @ue %e creado, seguraente segur aente tendría @ue ob8etar uc%os asectos del iso. Bo es un acto de arrogancia. Lo @ue 6o5 a %acer no es =s @ue una re6isión ro#esional, algo con lo @ue todos deberíaos sentirnos cóodos 5 algo @ue deberíaos agradecer si alguien lo %ace. ( tra6és de las críticas es coo odeos arender, coo %acen édicos, ilotos o abogados. E nosotros, coo rograadores, tabién teneos @ue arender a %acerlo. ainarlo. f)ien %ec%o erial-ate 6éase el Listado )14 es una clase @ue reresenta una #ec%a en Ja6a. H/ara @ué se necesita una clase @ue reresente una #ec%a si Ja6a 5a cuenta con 8a6a.util.-ate 5 8a6a.util.Calendar, entre otrasI *l autor creó esta clase coo resuesta a un roblea @ue 5o tabién %e adecido. *l coentario de su Ja6adoc inicial línea NO4 lo e>lica. /odríaos cuestionar su intención, ero 5o tabién %e su#rido este roblea 5 se agradece una clase sobre #ec%as en lugar de %oras.
Primero* conseguir 9ue funcione a5 6arias ruebas de unidad en la clase erial-ateTests 6éase el Listado )124. Todas son satis#actorias. -esa#ortunadaente, un r=ido e>aen deuestra @ue no corueban todos los asectos TU. /or e8elo, al reali!ar una b;s@ueda de usos en el étodo Mont%CodeToKuarter línea WWV4 se indica @ue no se usa VU. /or lo tanto, las ruebas de unidad no lo corueban. corueb an. /or ello, recurrí a Clo6er ara 6er el alcance de las ruebas de unidad. Clo6er indicó @ue las ruebas sólo e8ecutan 9 de las A instrucciones instrucc iones e8ecutables de erial-ate aro>iadaente el 0 or 004 T2U. *l aa de alcance uestra grandes #ragentos de código sin e8ecutar deserdigados or la clase. Mi ob8eti6o era corender la clase 5 re#actori!arla, algo @ue no odía lograr sin una cobertura a5or de las ruebas. /or ello dise3é i roia s%ite de ruebas de unidad indeendientes 6éase el Listado )1V4. i se #i8a en las ruebas, corobar= @ue uc%as est=n coentadas, 5a @ue no se sueraron. Reresentan un coortaiento @ue considero debería incluirse en erial-ate. /or tanto, al re#actori!ar erial-ate, intentaré @ue estas ruebas #uncionen. "ncluso con algunas de las ruebas coentadas, el in#ore de Clo6er indica @ue a%ora e8ecutan O0 el 92 or ciento4 de las A instrucciones e8ecutables. n gran resultado @ue creo @ue uedo e8orar. Las rieras ruebas coentadas líneas 2W1NW4 son un tanto retenciosas. *l rograa no #ue dise3ado ara ar a suerar estas ruebas, ero ero el coortaiento e arecía e6idente G2U. -escono!co or @ué se %a creado el étodo test7ee&da5CodeTotring ero 5a @ue est= a%í, arece ob6io @ue no debe distinguir entre a5;sculas 5 in;sculas. *l dise3o de las ruebas #ue sencillo TWU 5 =s toda6ía @ue #ueran satis#actorias sileente cabié las líneas 29 5 2NW ara usar e@uals"gnoreCase. Coenté las ruebas de las líneas W2 5 V 5a @ue no estaba seguro de si las abre6iaturas tues 5 t%urs se aditían o no. Las ruebas de las líneas W 5 V no se sueraron, aun@ue deberían %aberlo %ec%o G2U. /odeos corregirlas, 8unto a las ruebas de las líneas NW a la 2W, si reali!aos los siguientes cabios en la #unción stringToMont%Code. VO i# result ] 4 result ^ 244 _`Ob result X 1 VA #or int i X 0 i ] ont%Baes.lengt% iZZ4 _`Ob V9 i# s.e@uals"gnoreCases%ortMont%BaesiU44 _`Ob VN0 result X i Z VN brea& VN2 _`Od VNW i# s.e@uals"gnoreCaseont%BaesiU44 _`Ob VNV result X i Z VN brea& VNN _`Od VNO _`Od VNA _`Od La rueba coentada de la la línea WA descubre un error en el étodo getollo?ing-a5<#7ee& línea NO24. *l 2 de diciebre de 200V #ue s=bado 5 el siguiente s=bado #ue el de enero de 200. in ebargo, al e8ecutar la rueba, 6eos @ue getollo?ing-a5<#7ee& de6uel6e el 2 de diciebre coo siguiente s=bado desués del 2 de diciebre, un error e6idente GWU, TU. eos el roblea en la línea NA. *s un error de condición de líite tíico TU. -ebería ser lo siguiente: NA i# base-<7 ^X target7ee&da54 _`Ob Con6iene destacar @ue esta #unción su#rió una rearación anterior. *l %istorial de cabios línea VW4 uestra @ue se corrigieron los errores en get /re6ious-a5<#7ee&, getollo?ing-a5<#7ee& 5 getBearest-a5<#7ee& TNU. La rueba de unidad testGetBearest-a5<#7ee& línea W294, @ue rueba el étodo
getBearest-a5<#7ee& línea O04, inicialente no era tan e>tensa 5 coleta. (3adí ultitud de casos de rueba 5a @ue los iniciales no se sueraban TNU. /uede 6er el atrón de #allos si se #i8a en los casos de rueba coentados. *l atrón es re6elador TOU. Muestra @ue el algorito #alla si el día =s ró>io es de una #ec%a #utura. *6identeente se trata de alg;n tio de error de condición de líite TU. *l atrón de alcance de las ruebas generado or Clo6er tabién es interesante TAU. La línea O9 nunca se e8ecuta, lo @ue signi#ica @ue la instrucción i# de la línea OA siere es #alse, ero si nos #i8aos en el código, indica @ue debe ser true. La 6ariable ad8ust siere es negati6a 5 no uede ser a5or o igual a V, or lo @ue el algorito es incorrecto. ( continuación se uestra el algorito correcto: int delta X target-<7 1 base.get-a5<#7ee&4 int ositi6e-elta X delta Z O int ad8ust X ositi6e-elta O i# ad8ust ^ W4 ad8ust 1X O return erial-ate.add-a5s ad8ust, base4 /or ;ltio, las ruebas de la líneas VO 5 V29 se ueden suerar si se genera "llegal(rguent*>cetion en lugar de de6ol6er una cadena de error desde ?ee&"nMont%Totring 5 relati6eTotring. Con estos cabios, todas las ruebas de unidad se sueran 5 creo @ue a%ora erial-ate #unciona. Llega el oento de %acer @ue sea correcta.
"acer 9ue sea correcta -escribireos erial-ate de arriba a aba8o ara e8orarla en nuestro recorrido. (un@ue no lo 6eaos en este an=lisis, e8ecutaré todas las ruebas de unidad de JCoon, incluida i rueba de unidad e8orada ara erial-ate, con todos los cabios e#ectuados. /or ello, tenga la seguridad de @ue todos los cabios @ue 6ea #uncionan ara JCoon. *n la línea 6eos abundantes coentarios sobre in#oración de licencia, derec%os de autor, autores e %istorial de cabios. (suo @ue %a5 ciertos asectos legales @ue ostrar, or lo @ue los derec%os de autor 5 las licencias deben conser6arse. /or otra arte, el %istorial de cabios es una réora de la década de 9N0. (%ora teneos %erraientas de control de código #uente @ue se encargan de ello. a5 @ue eliinar este %istorial CU. La lista de iortación @ue coien!a en la línea N se uede reducir or edio de 8a6a.te>t. 5 8a6a.util.. JU Bo e con6ence el #orato TML del Ja6adoc línea NO4. n arc%i6o #uente con =s de un lengua8e e arece un roblea. *ste coentario tiene c%atro lengua8es: Ja6a, esa3ol, Ja6adoc 5 %tl GU. Con tantos lengua8es se %ace di#ícil antener la co%erencia. /or e8elo, la ubicación de las líneas O 5 O2 se ierde al generar el Ja6adoc 5 ade=s, H@uién @uiere 6er ]ul^ 5 ]li^ en el código #uenteI na estrategia =s acertada consiste en rodear el coentario con ]re^ ara @ue el #orato del código #uente se conser6e en el Ja6adoc9NU. La línea AN es la declaración de la clase. H/or @ué se le asigna el nobre erial-ateI HKué sentido tiene la alabra serialI H*s or@ue la clase se deri6a de
eriali!ableI /arece irobable. )asta de adi6inan!as. é or @ué o al enos eso creo4 se usa la alabra serial. La cla6e se encuentra en las constantes *R"(LL<7*R)<B- 5 *R"(L//*R)<B- de las líneas 9A 5 0. E una cla6e toda6ía e8or es el coentario de la línea AW0. *l nobre de la clase es erial-ate 5a @ue se ileenta con un n;ero de serie, @ue arece ser el n;ero de días desde el W0 de diciebre de A99. /ero esto suone un roblea. /or un lado, el térino Fn;ero de serie no es realente correcto. /uede ser un detalle enor ero la reresentación es =s un desla!aiento relati6o @ue un n;ero de serie. *l térino Fn;ero de serie tiene @ue 6er =s con arcadores de identi#icación de roductos @ue con #ec%as. /or ello, no lo considero esecialente descriti6o BU. n térino =s descriti6o sería Fordinal. *l segundo roblea es =s signi#icati6o. *l nobre erial-ate ilica una ileentación. *sta clase es abstracta. Bo es necesario @ue ili@ue nada sobre la ileentación de %ec%o, es aconse8able ocultarla. /or ello, creo @ue el nobre se encuentra en un ni6el de abstracción incorrecto B2U. *n i oinión, el nobre de esta clase debería ser sileente -ate. -esa#ortunadaente, %a5 deasiadas clases con el nobre -ate en la biblioteca de Ja6a, de odo @ue no es el =s adecuado. Coo esta clase traba8a con días 5 no %oras, odríaos usar -a5, ero 5a se s e usa en otros uc%os untos. (l #inal, oté or -a5-ate coo e8or oción. ( artir de a%ora, usareos -a5-ate. Recuerde @ue los listados @ue 6a a leer siguen usando erial-ate. *ntiendo or@ue -a5-ate se %ereda de Coarable 5 eriali!able. H/ero de Mont%ConstantsI La clase Mont%Constants 6éase el Listado )1W4 es una serie de constantes #inales est=ticas @ue de#inen los eses. eredar de clases con constantes es un 6ie8o truco @ue los rograadores de Ja6a usan ara e6itar e>resiones coo Mont%Constants.Januar5, ero es una ala idea J2U. Mont%Constants debería ser una enueración. ublic abstract class -a5-ate ileents Coarable, eriali!able _`Ob ublic static enu Mont% _`Ob J(B(RE4, *)R(RE24, M(RCW4, (/R"LV4, M(E4, JB*N4, JLEO4, (GTA4, */T*M)*R94, 4 _`Ob t%is.inde> X inde> _`Od ublic static Mont% a&eint ont%"nde>4 _`Ob
#or Mont% : Mont%.6alues44 _`Ob i# .inde> XX ont%"nde>4 return _`Od t%ro? ne? "llegal(rguent*>cetion"n6alid ont% inde> Z ont%"nde>4 _`Od ublic #inal int inde> _`Od (l cabiar Mont%Constants or esta enueración se odi#ica la clase -a5-ate 5 todos sus usuarios. Tardé una %ora en reali!ar todos los cabios. in ebargo, las #unciones @ue antes acetaban un 6alor int ara el es, a%ora acetan un enuerador Mont%. *sto signi#ica @ue odeos des%aceos del étodo isalidMont%Code línea W2N4 5 de la corobación de errores del código de los eses coo en ont%CodeToKuarter línea WN4 GU. Tras ello, en la línea 9, teneos serialersion"-. *sta 6ariable se usa ara controlar el se3ali!ador. i la cabiaos, con lo @ue todos los eleentos -a5-ate escritos con una 6ersión antigua del software ser=n ilegibles 5 se generar= "n6alidClass*>cetion. i no declara la 6ariable serialersion"-, el coilador genera una auto=ticaente 5 ser= di#erente cada 6e! @ue odi#i@ue el ódulo. Ea sé @ue todos los docuentos recoiendan el control anual de esta 6ariable, ero creo @ue el control auto=tico de la se3ali!ación es =s seguro GVU. -esués de todo, re#iero deurar una "n6alidClass*>cetion @ue el e>tra3o coortaiento @ue se roduciría si e ol6ido de cabiar serialersion"-. /or ello, eliinaré la 6ariable, al enos or a%ora9OU. Creo @ue el coentario de la línea 9W es redundante. Los coentarios redundantes sólo sir6en ara acuular entiras 5 desin#oración C2U. /or ello los eliinaré. Los coentarios de las líneas 9O 5 00 %ablan sobre n;eros de serie, @ue 5a %eos encionado antes CU. Las 6ariables @ue describen son la riera 5 ;ltia #ec%a osible @ue -a5-ate uede describir. /odríaos %acer @ue #uera =s claro BU. BU . ublic static #inal int *(RL"*T-(T*cel. a5 in#oración uc%o =s coleta en una 6ariante de -a5-ate: reads%eet-ate 6éase el Listado )14. *l coentario de la línea O describe este roblea. *l roblea arece relacionado con la ileentación de reads%eet-ate 5 no con -a5-ate. Mi conclusión es @ue *(RL"*T-(T*io. -e nue6o, siento la necesidad de cabiar las 6ariables a reads%eet-ate GNU. /ero una b;s@ueda r=ida de los usuarios de estas 6ariables uestra @ue otra clase las utili!a: Relati6e-a5<#7ee&Rule 6éase el
Listado )1N4, eos dic%o uso en las líneas OO 5 OA, en la #unción get-ate, donde se usan ara corobar @ue el arguento de get-ate sea un a3o 6=lido. *l dilea es @ue un usuario de una clase abstracta necesita in#oración sobre su ileentación. Tendreos @ue roorcionar esta in#oración sin containar -a5-ate. /or lo general, obtendríaos la in#oración de ileentación de una instancia de una 6ariante. in ebargo, la #unción get-ate no recibe una instancia de -a5-ate, aun@ue sí la de6uel6e, lo @ue signi#ica @ue debe crearla en alguna arte. La solución est= en las líneas AO120. La instancia -a5-ate se crea or edio de una de estas tres #unciones: get/re6ious-a5<#7ee&, getBearest-a5<#7ee& o getollo?ing-a5<#7ee&. i nos #i8aos en el listado -a5-ate, 6eos @ue estas #unciones líneas NWA1O2V4 de6uel6en una #ec%a creada or add-a5s línea O4, @ue in6oca create"nstance línea A0A4, @ue crea reads%eet-ate GOU. Bo es recoendable @ue las clases base cono!can sus 6ariantes. /ara corregirlo, debeos usar el atrón de factor+a abstracta9AU 5 crear -a5-ateactor5. \sta #actoría crear= las instancias de -a5-ate @ue necesitaos 5 tabién resonder= a reguntas sobre la ileentación, coo las #ec%as =>ia 5 ínia. ublic abstract class -a5-ateactor5 _`Ob ri6ate static -a5-ateactor5 #actor5 X ne? reads%eet-ateactor54 ublic static 6oid set "nstance-a5-ateactor5 #actor54 _`Ob -a5-ateactor5.#actor5 X #actor5 _`Od rotected abstract -a5-ate a&e-ateint ordinal4 rotected abstract -a5-ate a&e-ateint da5, -a5-ate.Mont% ont%, int 5ear4 rotected abstract -a5-ate a&e-ateint da5, int ont%, int 5ear4 rotected abstract -a5-ate a&e-ate8a6a.util.-ate date4 rotected abstract int getMiniuEear4 rotected abstract int getMa>iuEear4 ublic static -a5-ate a&e-ateint ordinal4 _`Ob return #actor5.a&e-ateordinal4 _`Od ublic static -a5-ate a&e-ateint da5, -a5-ate.Mont% ont%, int 5ear4 _`Ob return #actor5.a&e-ateda5, ont%, 5ear4 _`Od ublic static -a5-ate a&e-ateint da5, int ont%, int 5ear4 _`Ob return #actor5.a&e-ateda5, ont%, 5ear4 _`Od ublic static -a5-ate a&e-ate8a6a.util.-ate date4 _`Ob return #actor5.a&e-atedate4 _`Od ublic static int getMiniuEear4 _`Ob return #actor5.getMiniuEear4 _`Od ublic static int getMa>iuEear4 _`Ob return #actor5.getMa>iuEear4 _`Od _`Od *sta clase de #actoría sustitu5e los étodos create"nstance or étodos a&e-ate,
lo @ue e8ora ligeraente los nobres BU. -e #ora redeterinada es reads%eet-ateactor5 ero se uede cabiar or otra #actoría. Los étodos est=ticos delegados en étodos abstractos usan una cobinación de los patrones de instancia 8nica99U, decorador 00U 5 factor+a abstracta @ue considero u5 ;til. reads%eet-ateactor5 tiene este asecto: ublic class reads%eet-ateactor5 e>tends -a5-ateactor5 _`Ob ublic -a5-ate a&e-ateint ordinal4 _`Ob return ne? reads%eet-ateordinal4 _`Od ublic -a5-ate a&e-ateint da5, -a5-ate.Mont% ont%, int 5ear4 _`Ob return ne? reads%eet-ateda5, ont%, 5ear4 _`Od ublic -a5-ate a&e-ateint da5, int ont%, int 5ear4 _`Ob return ne? reads%eet-ateda5, ont%, 5ear4 _`Od ublic -a5-ate a&e-ate-ate date4 _`Ob #inal GregorianCalendar calendar X ne? GregorianCalendar4 calendar.setTiedate4 return ne? reads%eet-ate calendar.getCalendar.-(T*4, -a5-ate.Mont%.a&ecalendar.getCalendar.MiuEear4 _`Ob return reads%eet-ate.$(+"MME*(R//