capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de...

14
/ 14 capa_ a responsabilidade de cada um e como eles devem afetam todo o software e não somente uma funcio- ra de software em ambientes ágeis é que ela envol- como: será que implementando certa funcionalidade da arquitetura antes das outras, não estou criando deixando uma funcionalidade para depois não vou quitetura antes do código não estou deixando de ser Este artigo não tem o objetivo de apresentar em ambientes ágeis, mas apresentar várias práticas tas ou de forma individual. O fato de existirem essas a única forma de se lidar com arquitetura ágil. Essas práticas foram tiradas de experiências pessoais, de relatos de experiências e de conversas informais com amigos que já passaram por essas experiências. Sen- do assim, representam práticas do mundo real e não apenas teorias que ninguém nunca experimentou. como elas se relacionam e podem ser combinadas. Arquitetura Cartoon da arquitetura em um projeto ágil é o medo de se é arriscado pular direto para o código sem pensar sitos não-funcionais, pois isso pode gerar um risco de retrabalho grande no futuro. Outro problema é duplicado, isso diminui o reúso de código dentro da arquitetura e a torna heterogênea. lhar em cima da arquitetura sem gastar muito tem- rais para lidar com os principais requisitos não-fun- cionais e compartilhar esse entendimento com toda Arquitetura em Práticas para Lidar com Aprenda as principais práticas que são utilizadas para lidar com arquitetura em empresas que adotaram com sucesso o uso de métodos ágeis. ambientes ágeis

Transcript of capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de...

Page 1: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 14

capa_

!"#$%&%#!'()&(*+,%-'!&(.(#/(0+10&$%+()$,20$3()&(*&!( )&4(1$)+5( 6+!./( &7$*%&( 0+1*&1*+( '( !&*6&$%+( )&('38#/'*( 0'!'0%&!2*%$0'*9( ( '!"#$%&%#!'( )&( *+,%-'!&(&1:+3:&( #/'( !&6!&*&1%';<+( '=*%!'%'( )+*( %$6+*( )&(0+/6+1&1%&*( )&( #/( *+,%-'!&5( )&( ,+!/'( '( )&4(1$!(a responsabilidade de cada um e como eles devem $1%&!'8$!9( *()&0$*>&*('!"#$%&%#!'$*(*<+('"#&3'*("#&(afetam todo o software e não somente uma funcio-1'3$)')&(+#(6&)';+9

?/'()'*()$4(0#3)')&*()&(*&(3$)'!(0+/('!"#$%&%#@ra de software em ambientes ágeis é que ela envol-:&()&0$*>&*("#&(',&%'/(%+)+(*+,%-'!&9(A&1)+('**$/5(6+)&(*&!(/#$%+('!!$*0')+($81+!'!(0&!%'*("#&*%>&*('!@"#$%&%#!'$*(&/($%&!';>&*($1$0$'$*5(6+$*($**+(6+)&(8&@!'!(#/(8!'1)&(!&%!'='3B+()&6+$*9(C$D@*&("#&(*&()&:&(3$)'!( 0+/( &**'*( )&0$*>&*( '!"#$%&%#!'$*( 1+( EF3%$/+(/+/&1%+( !&*6+1*G:&3H5( 6+!./( &**&( /+/&1%+( 1<+(.( '38+( %!$:$'3( )&( *&( )&*0+=!$!9(C'2( *#!8&/("#&*%>&*(como: será que implementando certa funcionalidade da arquitetura antes das outras, não estou criando #/()&*$81(0+/63&7+()&/'$*('1%&*()'(B+!'I(A&!G("#&(deixando uma funcionalidade para depois não vou 8&!'!(/#$%+(!&%!'='3B+I(A&!G("#&(%!'='3B'1)+(1'('!@quitetura antes do código não estou deixando de ser G8$3I(

Este artigo não tem o objetivo de apresentar #/'(*+3#;<+()&4(1$%$:'(6'!'(*&(3$)'!(0+/('!"#$%&%#!'(em ambientes ágeis, mas apresentar várias práticas "#&(6+)&/(*&!(#%$3$D')'*(6'!'(*&(3$)'!(0+/()&0$*>&*('!"#$%&%#!'$*9( J3'*( 6+)&/( *&!( #%$3$D')'*( %+)'*( K#1@tas ou de forma individual. O fato de existirem essas 6!G%$0'*(1<+(*$81$4(0'(%'/=./("#&(&3'*(!&6!&*&1%'/(a única forma de se lidar com arquitetura ágil. Essas

práticas foram tiradas de experiências pessoais, de relatos de experiências e de conversas informais com amigos que já passaram por essas experiências. Sen-do assim, representam práticas do mundo real e não apenas teorias que ninguém nunca experimentou.

*( *&;>&*( *&8#$1%&*( '6!&*&1%'/( *&$*( 6!G%$0'*(6'!'('!"#$%&%#!'(G8$3(&(1'(F3%$/'(*&;<+(.(/+*%!')+(como elas se relacionam e podem ser combinadas. L#!$+*+(6'!'(*'=&!("#'$*(*<+('*(6!G%$0'*I(J1%<+(*$8'(6'!'('(6!M7$/'(*&;<+N(

Arquitetura Cartoon?/'( )'*( "#&*%>&*( "#&( &1:+3:&/( '( )&4(1$;<+(

da arquitetura em um projeto ágil é o medo de se &/6!&8'!(/#$%+(&*,+!;+(1+()&*&1B+()'('!"#$%&%#!'('1%&*( )+( 6!+K&%+( 0+/&;'!9( O+!( +#%!+( 3')+5( %'/=./(é arriscado pular direto para o código sem pensar 1'*(6!$10$6'$*("#&*%>&*(!&3'0$+1')'*(0+/(+*(!&"#$@sitos não-funcionais, pois isso pode gerar um risco de retrabalho grande no futuro. Outro problema é +*( )&*&1:+3:&)+!&*( 0+/&;'!&/( 0')'( #/( '( )&*&1@:+3:&!(*#'(6!M6!$'(*+3#;<+(6'!'(+(/&*/+(6!+=3&/'(1'('63$0';<+9(P&*/+("#&(+(0M)$8+(&/(*$(1<+(&*%&K'(duplicado, isso diminui o reúso de código dentro da arquitetura e a torna heterogênea.

P'*("#'3(.(+( 3$/$%&I(A&!G("#&(.(6+**2:&3(%!'='@lhar em cima da arquitetura sem gastar muito tem-6+(8&!'1)+()+0#/&1%';>&*(-!$%&@+13Q(R+#(*&K'5("#&(1$18#./(:'$(3&!SI(L+/+()&4(1$!(*+3#;>&*('!"#$%&%#@rais para lidar com os principais requisitos não-fun-cionais e compartilhar esse entendimento com toda '(&"#$6&I(((

?/'(6!G%$0'("#&(3$)'(0+/(&**&(6!+=3&/'(.('(0B'@

Arquitetura em Práticas para Lidar com

Aprenda as principais práticas que são utilizadas para lidar com arquitetura em empresas que adotaram com sucesso o uso de métodos ágeis.

ambientes ágeis

Page 2: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

15 \

Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-suem um impacto grande em porções locais do código, porém mui- !"# $%&%"# '()# ! *'+%,#)# )-.% *$)# /%#,!' %0# 1,!# 2)'"*" 3'2*!# '!#arquitetura de toda a aplicação. Desse fato, surgem questões a res-peito do quanto se deve dedicar ao projeto da arquitetura antes da implementação ou quando se deve trabalhar em refatorações para adequar requisitos não-funcionais. O objetivo deste artigo é apre-sentar algumas práticas para lidar com arquiteturas ágeis.

!"#$!%&'"($$#&)&*"($$#+,"-!%./0%,/1$&)&+(,*"($$#

Desenvolvedor de frameworks, pesquisador em design de software, editor-chefe da revista MundoJ e professor do ITA, onde 2)'241*1#"1!#+0!/1!5()6#,%" 0!/)#%#/)1 )0!/)7#8)""1*#/*$%0"!"#2%0 *92!5:%"#/!#;4! !<)0,!#=!$!#%#%>;%0*3'2*!#2),)#!0?1* % )#/%#

software nas plataformas Java SE, Java EE e Java ME. Participou de projetos open-source, como SwingBean e JColtrane, e acredita ?1%#1,#-),#")< @!0%#"%#<!&#,!*"#2),#20*! *$*/!/%#/)#?1%#2),#2A/*+)7

/')'( !"#$%&%#!'( L'!%++19( ( !"#$%&%#!'( L'!%++1(.(#/'(6!G%$0'(1'("#'3( +( '!"#$%&%+( ,'D(#/()&*&1B+(3$:!&(6'!'('(!&6!&*&1%';<+()+*(6!$10$6'$*(&3&/&1%+*()'( '!"#$%&%#!'9( 3./( )+*( %!')$0$+1'$*( !&%T18#3+*5(bolinhas e setinhas, também é recomendável inserir 48#!'*(+#(20+1&*("#&(!&6!&*&1%'/()&(/'1&$!'(/'$*(:$*#'3(+*(&3&/&1%+*(&(0+/6+1&1%&*()&41$)+*(1'('!-quitetura.

» O'!'("#&(4"#&(/'$*(03'!+(0+/+(&**&(%$6+()&(!&-6!&*&1%';<+(6+)&(*&!(,&$%+5(:'/+*('(#/(&7&/-63+9(U/'8$1&(#/'('63$0';<+(&/("#&(+(#*#G!$+(precise solicitar relatórios que são gerados a 6'!%$!()&(#/'(='*&()&()')+*9(C&:$)+(V(0+/63&-xidade dos relatórios e ao tamanho da base de dados, cada relatório pode demorar um tempo 6'!'(*&!(6!+0&**')+9(W&**&(0&1G!$+5('(6'!%$!()&(0+1:&!*'*(0+/(+*(03$&1%&*5(,+!'/($)&1%$40')+*(os seguintes requisitos:

» X(#*#G!$+(1<+()&:&(40'!('8#'!)'1)+(6'!'(*'-=&!( *&( *#'( !&"#$*$;<+()&( !&3'%M!$+( &*%G( *&1)+(processada.

» ?/'("#'1%$)')&(8!'1)&()&(!&3'%M!$+*(0+/63&-xos rodando ao mesmo tempo pode derrubar o servidor, então a arquitetura deve ter uma forma de controlar sua carga máxima de pro-cessamento simultâneo.

» Relatórios gerados para um usuário devem po-der ser recuperados novamente sem a necessi-dade de um novo processamento.

C&6+$*()&(6&1*'!('(!&*6&$%+()&(0+/+(!&*+3:&!$'(+(6!+=3&/'5(,+$(,&$%+(+()&*&1B+('6!&*&1%')+(1'(48#!'(Y9( 0B+("#&(1&**&( 6+1%+( :'3&( '( 6&1'( !&**'3%'!( "#&()&/+!&$(/&1+*()&(Z[(/$1#%+*(6'!'(,'D&!(&**&()&*&-

1B+9(X($1:&*%$/&1%+(&/(%&/6+(6'!'('(0!$';<+()&**'('!"#$%&%#!'(0'!%++1(1<+()&:&(*&!(/#$%+(8!'1)&9(?/'('3%&!1'%$:'(*&!$'(,'D&!(&**&()&*&1B+(&/(#/("#')!+(branco, por exemplo. O ideal é tentar representar tudo que for mais importante em um único desenho, porém nada impede que sejam feitos dois ou três de-*&1B+*(0+/(,+0+*(&/()$,&!&1%&*("#&*%>&*9(\&**'3%+(aqui que quanto maior for a quantidade de desenhos &( )&%'3B&*( !&3'%$:+*( '( "#&*%>&*( /'!8$1'$*5( /&1+*('%&1;<+(*&!G()')'('+("#&(!&'3/&1%&(.($/6+!%'1%&9((

( '!"#$%&%#!'( 0'!%++1( )&:&( ,+0'!( 1'*( *+3#;>&*(para os requisitos não-funcionais mais importantes 6'!'('('!"#$%&%#!'(&/("#&*%<+9(W+(&7&/63+('6!&*&1-tado, o foco foi em como os relatórios serão proces-*')+*5('!/'D&1')+*(&( !&0#6&!')+*9(X()&*&1B+(1<+(representa, por exemplo, como irá funcionar a se-8#!'1;'()&1%!+()'('63$0';<+9(X(/+%$:+(.("#&(isso não foi considerado um requisi-to crítico no mo-mento e que não oferece muito risco de ser imple-mentado depois. Em um sistema em que a assinatura digital de documentos fosse um requi-sito importante, por exemplo, certamente a represen-%';<+( )'( '!"#$%&%#!'(incluiria algo a res-peito.

W+%&(%'/=./("#&(

Page 3: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 16

6&3'('!"#$%&%#!'(.(6+**2:&3($)&1%$40'!(+*(6!$10$6'$*(%$-pos de componentes da arquitetura, como parâmetro do relatório, processador de relatórios, controller e C X9(X=*&!:&("#&(%'/=./(40'/(=&/(03'!'*('38#/'*()&0$*>&*( '!"#$%&%#!'$*9( ?/( &7&/63+( .( 1'( ,+!/'( &/("#&(+*(!&3'%M!$+*(*&!<+('!/'D&1')+*](&/(#/'(='*&()&(dados diferente da que contém os dados, no formato OC^(&(#*'1)+(#/'(='*&()&()')+*(1<+@!&3'0$+1'39(X#-%!'()&0$*<+("#&(40'(=&/(03'!'(.(+(,'%+()'*(*+3$0$%';>&*()&(!&3'%M!$+(*&!&/(&1:$')'*(6'!'(#/'(43'5()'("#'3(+*(processadores de relatório as vão retirando e proces-sando assincronamente.

(6'!%$!()+()&*&1B+5('(&"#$6&()&:&(*&(!&#1$!(6'!'()$*0#%$!(&(0+/6'!%$3B'!(+(0+1B&0$/&1%+(&/(!&3';<+('*()&0$*>&*(%+/')'*9(J**&()&*&1B+(.(#/(=+/(0'1)$)'%+('(*&!(47')+(&/('38#/(3+0'3(:$*2:&3()+('/=$&1%&(+1)&(40'('(&"#$6&9(J3&(1<+()&:&(*&!(0+1*$)&!')+(0+/+('38+(imutável, mas como um rascunho de como pretende--se estruturar em alto nível a arquitetura para lidar com os principais requisitos não-funcionais.

?/'( )'*( :'1%'8&1*( )&**&( ,+!/'%+( /'$*( 3$:!&(é que ele facilita a discussão da arquitetura com os 03$&1%&*9( _&1)+( #/( &1%&1)$/&1%+( '=*%!'%+( *+=!&(como as coisas são tratadas no software, o cliente consegue entender e dar um maior feedback sobre '*( *+3#;>&*(&/6!&8')'*9(_$:&(#/'(&76&!$`10$'(6&*-soal em que essa prática foi usada em um projeto, no

qual em toda reunião com o cliente ele vinha com o )&*&1B+()'('!"#$%&%#!'(E)&='$7+()+(=!';+H9(O+!(&**&(motivo é importante que a arquitetura cartoon foque 1'*()&0$*>&*()&('!"#$%&%#!'(&(1<+(&1%!&(&/()&%'3B&*('(respeito de que tecnologias ou frameworks serão uti-3$D')+*(6'!'(0')'(0'/')'9(

a$)&( 0+/( '( '%#'3$D';<+( )'( '!"#$%&%#!'( 0'!%++1(0+/+("#'3"#&!(+#%!+(%$6+()&()+0#/&1%';<+(&/(#/('/=$&1%&( G8$3]( R'S( *&( '38#/'( 0+$*'(/#)+#5(/'*( &3&(0+1%$1#'(*&1)+(F%$3(/&*/+(1<+(!&6!&*&1%'1)+(Y[[b('(!&'3$)')&5()&$7&(&3&(0+/+(&*%Gc(R=S('('%#'3$D';<+()&:&(ser importante para a equipe compartilhar melhor o &1%&1)$/&1%+()'('!"#$%&%#!'5(&1%<+('%#'3$D&@+c(R0S(*&(&3&(KG(0#/6!$#(*&#(6!+6M*$%+(&(*#'('%#'3$D';<+(1<+($!G(%!'D&!(/#$%+*(=&1&,20$+*5(&1%<+(K+8#&@+(,+!'9(

User Story ExperimentalC&6+$*()&(*&!(8&!')'('('!"#$%&%#!'(0'!%++15("#&(

representa de uma forma bem abstrata como os prin-cipais requisitos não-funcionais serão abordados, é 6!&0$*+()&*0&!(&**&(12:&3(6'!'()&41$!()&(,+!/'(/'$*(concreta como as coisas irão funcionar. Como uma )'*( )$!&%!$D&*( )+(/'1$,&*%+( G8$3( .( )'!( 6!&,&!`10$'( '(software funcionando no lugar de uma documenta-;<+(0+/6!&&1*$:'5(1<+(,'!$'(/#$%+(*&1%$)+(1&**&(/+-/&1%+(0+/&;'!('(&*0!&:&!()+0#/&1%';<+(0+/(&**'*()&0$*>&*9(J**'(6!G%$0'(*&(='*&$'(1+( ,'%+()&("#&(&**&(.(#/(=+/(/+/&1%+(6'!'(0+/&;'!('(E0+3+0'!('(/<+H(1+(0M)$8+(6'!'()&41$!(0+/+('*(0+$*'*(!&'3/&1%&($!<+(funcionar.

C&**'(,+!/'5()&:&(*&!(&*0+3B$)'(#/'(?*&!(A%+!Q(+#(#/(0+1K#1%+()&(?*&!(A%+!$&*("#&(*&K'/(,#10$+1'3-/&1%&(*$/63&*5(/'*("#&(&763+!&/()&( ,+!/'(*$81$4-cativa as camadas da arquitetura. O objetivo é que a $/63&/&1%';<+()&**'*(?*&!(A%+!$&*(J76&!$&1%'$*(*$!-va como exemplo para as próximas funcionalidades. J**&( .( +(/+/&1%+( 6'!'( )&41$!( "#'$*( ,!'/&-+!d*( &("#'$*('=+!)'8&1*(*&!<+(#%$3$D')'*9(

W+(&7&/63+('6!&*&1%')+(1'(48#!'(Y5(&7$*%&/()$-:&!*'*()&0$*>&*("#&(6!&0$*'/(*&!(%+/')'*9(X*(&7&/-plos mais simples envolvem escolher as tecnologias "#&(*&!<+(#%$3$D')'*(6'!'('(0!$';<+()'(0'/')'(-&=(&()'(0'/')'()&(6&!*$*%`10$'9(W+(0'*+()'(0'/')'()&(6&!*$*-%`10$'5(6+!(&7&/63+5()&:&!<+(0+1:$:&!()#'*(*+3#;>&*(sendo uma para o banco de dados relacional e outra 6'!'(+(='10+()&()')+*(W+Aea9(U103#*$:&('(6!M6!$'(&*-0+3B'()&("#'3(='10+()&()')+*(*&!G(#%$3$D')+(6'!'('!-/'D&1'!(+*(!&3'%M!$+*(,'D(6'!%&()&**'*(&*0+3B'*9( 3./()$**+5('$1)'()&:&@*&(3&:'!(&/(0+1*$)&!';<+(0+/+(*&!G(,&$%'('($/63&/&1%';<+()'*(43'*(6'!'(+(6!+0&**'/&1%+('**210!+1+5(0'*+()&*&K&@*&(#*'!(fPA("#'3(*&!:$)+!()&(/&1*'8&1*(*&!G(#*')+5("#&(,!'/&-+!d(*&!G(#%$3$D')+(6'!'(8&!';<+()+*(!&3'%M!$+*(&/(OC^(&%09

Enquanto na arquitetura cartoon não existe mui-%'(6!&+0#6';<+(0+/(+*()&%'3B&*5(1&**&(/+/&1%+(&3&*(*<+(/#$%+($/6+!%'1%&*(&(6+)&/(!&6!&*&1%'!()&0$*>&*(

23*"$#&4/ Arquitetura Cartoon desenvolvida para o exemplo.

Page 4: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

17 \

"#&( 6+)&/( $1g#&10$'!( %+)'*( '*( ,#10$+1'3$)')&*( 1+(,#%#!+9(P#$%'*(:&D&*(#/(*$/63&*()&%'3B&(1<+(*#6+!-%')+( $1:$'=$3$D'( '( #%$3$D';<+( )&( #/( ,!'/&-+!d( "#&(havia sido considerado. Retomando o exemplo, um )&%'3B&($/6+!%'1%&()&(*&!()&41$)+(*&!$'(0+/+('*(43'*()&( *+3$0$%';>&*( *&!$'/(+!8'1$D')'*](B':&!G(#/'(43'(6'!'(0')'(%$6+()&(*+3$0$%';<+I( *(43'*()&(*+3$0$%';<+(%&!<+('38#/(%$6+()&(6!$+!$)')&I(

J7$*%&/()&%'3B&*("#&(6+)&/(+#()&:&/(*&!()&4-1$)+*( 6+*%&!$+!/&1%&5( 6+!./(/#$%'*( :&D&*( 1'( B+!'()&(0+3+0'!('(E/<+(1'(/'**'H(&($/63&/&1%'!5('38#/'(*+3#;<+(6!&0$*'(*&!()')'(1+(/+/&1%+9(W&**&*(0'*+*(procure escolher sempre a mais simples! Porém, se nesse momento perceba-se que é uma decisão com chances de mudar no futuro e que poderá gerar um 8!'1)&($/6'0%+(0'*+(*&K'('3%&!')'5('(/&3B+!(+6;<+(.(isolar esse detalhe em uma classe ou método, não a )&$7'1)+(*&(&*6'3B'!(6&3'(='*&()&(0M)$8+9(C&$7&(*&6'-radas coisas que mudam em velocidades diferentes!

( $/63&/&1%';<+( )&**'( ?*&!( A%+!Q( J76&!$/&1-tal, além de agregar valor para o próprio negócio do 03$&1%&5(*&!:&(0+/+(,&&)='0d(6'!'('*()&0$*>&*('!"#$-%&%#!'$*( %+/')'*9( %!':.*( )&( #/'( $/63&/&1%';<+(mais concreta, é possível validar se as ideias que fo-!'/(!&6!&*&1%')'*(1'('!"#$%&%#!'(0'!%++1(,'D&/(*&1-%$)+(1'(6!G%$0'9(W')'( $/6&)&("#&(1&**&(6+1%+('('!-quitetura seja repensada e alterada. É justamente por $**+("#&(&**'('%$:$)')&(&*%G(*&1)+(!&'3$D')']()&%&0%'!(de forma precoce detalhes da arquitetura que podem não ser adequados aos requisitos não-funcionais da '63$0';<+9

W&**&(/+/&1%+5(+*(/&/=!+*()'(&"#$6&("#&(&*%$-:&!&/(3$)'1)+(0+/(&**'($/63&/&1%';<+(%`/('(3$=&!-)')&( )&( &76&!$/&1%'!( )$:&!*'*( %&01+3+8$'*( &( :&!$4-car qual será mais adequada. Pode-se, por exemplo, 0!$'!()#'*($/63&/&1%';>&*()+(0+1%!+33&!(#*'1)+(,!'-/&-+!d*()$,&!&1%&*(6'!'(:&!$40'!("#'3(*&($1%&8!'(/&-3B+!( 0+/( +*( +#%!+*( ,!'/&-+!d*( #%$3$D')+*9( O+)&@*&(%'/=./(!&'3$D'!(=&10B/'!d*(6'!'(:&!$40'!("#'3()'*(+6;>&*(&7$*%&1%&*(.(/&3B+!(&/(%&!/+*()&('38#/(!&-"#$*$%+(1<+@,#10$+1'39(W+(&7&/63+('6!&*&1%')+5(#/'(:'3$)';<+( )&( #/'( &*0+3B'( '!"#$%&%#!'3( $/6+!%'1%&(

*&!$'( :&!$40'!( *&( +( #*+( )&( #/'( ='*&( 1<+@!&3'0$+1'3(6'!'( +( '!/'D&1'/&1%+( )+*( !&3'%M!$+*( .( !&'3/&1%&(adequada.

W'( $/63&/&1%';<+( )&**'( ?*&!( A%+!Q( $1$0$'35( .(importante observar possíveis funcionalidades ou %!&0B+*()&(0M)$8+("#&(6+)&!$'/(*&!(!&#%$3$D')+*(6'!'(+#%!'*(?*&!(A%+!$&*9(O+!(/'$*("#&(6'!&;'("#&( $**+(.(,'D&!(+()&*$81(#6,!+1%5('38#/'*(*+3#;>&*($1%&3$8&1%&*(&/(0&!%+*(6+1%+*()'('!"#$%&%#!'(6+)&/(,'D&!(8!'1)&()$,&!&1;'(1'(:&3+0$)')&()&()&*&1:+3:$/&1%+()+(%$/&9(O limite que eu sugiro nesse ponto é: nunca crie có-digo para coisas que não vai precisar na funcionali-dade corrente, porém isole partes do código em que vê potencial de reúso para que possam ser facilmente !&#%$3$D')'*9(

Arquitetura de testesPessoalmente já vi vários desenvolvedores dei-

xarem de criar testes por não saberem como criar os %&*%&*( 6'!'( #/( )&%&!/$1')+( 0+/6+1&1%&9( +( 0+1-trário do que algumas pessoas pensam, criar testes não é uma atividade simples e exige uma curva de '6!&1)$D')+( !'D+G:&39( P#$%+*( )&*&1:+3:&)+!&*( &*-tudam técnicas de design e novos frameworks, mas não admitem gastar muito tempo com o estudo dos testes. Essa barreira inicial para que a equipe crie efe-%$:'/&1%&(%&*%&*('#%+/'%$D')+*(6+)&(*&!(#/'(8!'1-)&('/&';'(V(0+=&!%#!'()&(%&*%&*(1+(6!+K&%+5(&**&10$'3(para qualquer método ágil.

X( )&*&1:+3:$/&1%+( )'( 6!$/&$!'( ?*&!( A%+!Q( J7-6&!$/&1%'3(&1:+3:&(#/'(6!+8!'/';<+(/'$*(&763+!'-%M!$'5(&/("#&(/#$%'*(:&D&*(+(/'$*($/6+!%'1%&(.(&1-%&1)&!(0+/+(,#10$+1'(#/(,!'/&-+!d(+#(:&!$40'!(*&(.(possível que dois componentes diferentes trabalhem de forma integrada. Segundo o que o próprio Kent Beck disse em uma entrevista para a Software Engi-1&&!$18(\')$+5(&**'(.(#/'()'*(*$%#';>&*(&/("#&(+(#*+()+(_CC(1<+(.(%<+(1&0&**G!$+9

J**'(6!G%$0'(6!+6>&("#&(1<+('6&1'*('('!"#$%&%#!'(*&K'()&41$)'5(/'*(%'/=./(#/'('!"#$%&%#!'(6'!'3&3'(de como os testes de unidade devem ser feitos para 0')'( %$6+( )&( 0+/6+1&1%&9( U/'8$1&( #/'( '63$0';<+(

E as metáforas? (/&%G,+!'(.(#/'(6!G%$0'("#&(,+$('6!&*&1%')'(1'(6!$/&$!'(:&!*<+()'(J7%!&/&(O!+8!'//$18(0+/+(

#/'()'*(6!G%$0'*(6!$10$6'$*()'(/&%+)+3+8$'9(h+K&(&/()$'(KG(&7$*%&(#/(0+1*&1*+("#&(+(#*+()&(/&%G,+!'*(1<+(.(&**&10$'35(6+!./5("#'1)+(*<+(#%$3$D')'*5(&3'*(,'0$3$%'/('()$*0#**<+(&(0+/6!&&1*<+()'('!"#$%&%#!'(&1%!&(+*(/&/=!+*()'(&"#$6&9( ('!"#$%&%#!'(0'!%++1(.(#/'(M%$/'(+6+!%#1$)')&(6'!'(6!+0#!'!(/&%G,+!'*("#&(*&(&10'$7&/(1'(*+3#;<+('!"#$%&%#!'3(&*0+3B$)'9

X(1+/&()&()$:&!*+*(6')!>&*()&(6!+K&%+(#%$3$D'(/&%G,+!'*5(0+/+(X=*&!:&!5( )'6%&!5(P&)$'%+!(&%09(U**+(%'/=./(*&(!&6&%&(6'!'(6')!>&*('!"#$%&%#!'$*(0+/+(^$3%&!5(O$6&5(i!+d&!5(P'*%&!@A3':&(&%09( 6!+-:&$%&(+*(1+/&*()+*(6')!>&*("#&( ,+!&/(0&1%!'$*(6'!'( !&*+3:&!(+*(6!+=3&/'*()'( *#'('!"#$%&%#!'(6'!'(0!$'!(/&%G,+!'*(6'!'('*(*+3#;>&*(&(!&6!&*&1%G@3'*()&(#/'(,+!/'(/'$*(,G0$3()&(*&!(0+/6!&&1)$)'(&/(*#'(arquitetura cartoon.

Page 5: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 18

com três camadas: controller web, negócio e aces-*+('()')+*9( (0'/')'()&(0+1%!+33&!($1%&!'8&(*&/6!&(como uma classe de negócio e, dessa forma, na ar-"#$%&%#!'()&(%&*%&*(*&!$'()&41$)+("#&(6'!'(+(%&*%&()&(unidade do controller precisaria ser criado um mock para o objeto da camada de negócios. Para a camada de acesso a dados, precisaríamos de um framework )&(%&*%&*("#&(1+*(6&!/$%$**&($1$0$'3$D'!(&(:&!$40'!()+*()')+*()+(='10+5(0+/+(+(Ci?1$%5(6+!(&7&/63+9(L+/+(cada tipo de componente possui suas responsabilida-)&*(&(0+3'=+!';>&*()&1%!+()'()&41$;<+()'('!"#$%&%#-!'5('($)&$'(.("#&('(6'!%$!()$**+(*&K'()&41$)+(0+/+(0')'(um deles deve ser testado.

()&41$;<+( )'( '!"#$%&%#!'( )&( %&*%&*( .( #/'( '%$-vidade que pode ser desenvolvida paralelamente a $/63&/&1%';<+()'(?*&!(A%+!Q(J76&!$/&1%'39(A&(:+0`(KG()&*&1:+3:&!(&**'(?*&!(A%+!Q(#*'1)+(_CC5('('!"#$-tetura de testes irá surgir naturalmente, porém mui-%'*( :&D&*(1<+(.( '**$/("#&('0+1%&0&9(L+/+(&**&(.(+(momento de se explorar as possibilidades do que de 0!$'!(,#10$+1'3$)')&5(+*(%&*%&*('0'='/(40'1)+(/&$+(de lado. Se essa for a abordagem adotada, é impor-%'1%&(:+3%'!('+(0M)$8+@,+1%&(6'!'('(0!$';<+()+*(%&*%&*9((

Quando se revisita o código considerando sua %&*%'=$3$)')&5(6+)&(*&!("#&('38#/'*(!&,'%+!';>&*(*&-jam necessárias para deixar o código mais testável. O+)&(*&!("#&(*&K'(6!&0$*+(0!$'!(1+:'*('=*%!';>&*(&/(forma de interface, por exemplo, para que uma de-

pendência possa ser substituída por um mock. Outra coisa que é importante ser observada é a forma que os objetos são criados para que as dependências possam ser facilmente substituídas por mocks. O uso de pa-)!>&*(0+/+(^'0%+!Q5(C&6&1)&10&(U1K&0%$+1(&(A&!:$0&(a+0'%+!(R+()+('!%$8+()+(P'!%$1(^+-3&!5(1<+(+()+(f':'-JJ(O'%%&!1*S(*<+(!&0+/&1)G:&$*(1&**&*(0'*+*9((

W&**&(/+/&1%+5('38#/'*()$40#3)')&*(6+)&/(*&!(&10+1%!')'*(1'(B+!'()&(!&'3$D'!(+*(%&*%&*9(P&*/+("#&(#/'( )&%&!/$1')'( OU( 6+**#'( $1%&!,'0&*( &( *&K'5( 6+!(exemplo, injetada na classe, ele pode ser bem com-63$0')'()&(/+0d'!9(?/(&7&/63+(.('( OU(fPA5("#&($1-03#*$:&(*&!$'(#/'(8!'1)&(0'1)$)'%'(6'!'(,'D&!(+(6!+-cessamento assíncrono no exemplo apresentado. Pra &1:$'!(#/'(/&1*'8&/(1&**'( OU( .(1&0&**G!$+( 0!$'!(diversos objetos, sendo um criado pelo outro, invo-cando diversos métodos, o que é um verdadeiro pe-*')&3+(6'!'(*&(/+0d'!9(?/'(*+3#;<+(*&!$'($*+3'!(+(#*+()&**'( OU(&/(#/'(03'**&()'('63$0';<+(0+/(#/(*$/-63&*( /.%+)+( &1:$'!P&1*'8&/RS9( O+!( &**&( 6+1%+( )&(:$*%'5('(0!$';<+()'('!"#$%&%#!'()&(%&*%&*(%&/(+(6'6&3(também de ajudar a desacoplar as classes da aplica-;<+5(:'3$)'1)+(*&(&3'*(*<+(!&'3/&1%&(%&*%G:&$*9

O código de testes pode sofrer dos mesmos pro-=3&/'*()&(#/(0M)$8+()&(6!+)#;<+](*&!()&()$,20$3( 3&-gibilidade, conter código duplicado etc. Essas falhas 1+()&*$81()+*(%&*%&*(6+)&/(0!$'!()$40#3)')&*()&*1&-0&**G!$'*('+(*&(%!'='3B'!(0+/(+*(%&*%&*9(?/'(,!'*&()&(

Componentes Reutilizáveis em Arquitetura Ágil – Um caso real!W+()$'(jk()&(*&%&/=!+()&*%&('1+(4D(#/'('6!&*&1%';<+(1'(%!$3B'()'($1)F*%!$'()+(&:&1%+(LiA+,%(,'-

3'1)+(*+=!&(#/'('!"#$%&%#!'()&(#/'('63$0';<+(!&'3(1'("#'3(,+!'/(#%$3$D')+*('*6&0%+*(&(/&%')')+*(6'!'('#/&1%'!(+(!&F*+(&(6&!/$%$!('(&:+3#;<+()'('!"#$%&%#!'9(W&**'('63$0';<+5(#/(!&"#$*$%+(1<+@,#10$+1'3($/-6+!%'1%&(&(!&0+!!&1%&(&/(:G!$'*(,#10$+1'3$)')&*(&!'("#&(+*(#*#G!$+*(6!&0$*'!$'/(*&!(1+%$40')+*("#'1)+(+#%!+(4D&**&(#/'('3%&!';<+(1+*()')+*("#&(&*%':'/(*&1)+(:$*#'3$D')+*9(L+/+(&!'(#/'('63$0';<+(-&=5($**+(6!&0$*'!$'(*&!(,&$%+(#%$3$D'1)+( f l(!&:&!*+9(U**+(&!'(0+1*$)&!')+(6+!(%+)+*(#/(,'%+!()&(!$*0+(1'(arquitetura.

A&8#$1)+('(6!G%$0'('6!&*&1%')'5(#/'(,#10$+1'3$)')&("#&(#%$3$D':'(&**&(!&0#!*+(,+$(&*0+3B$)'(6'!'(*&!('(6!$/&$!'('( *&!()&*&1:+3:$)'9(C#!'1%&(&**'( $/63&/&1%';<+( $1$0$'35(6!+0#!+#@*&()&$7'!(+(#*+()+( f l(!&:&!*+(+(/'$*(*$/63&*(6+**2:&3()&(*&!(#%$3$D')+(6+!(+#%!'*(,#10$+1'3$)')&*9(W+(0'*+5(,+$(#%$3$D')+(#/('*6&0%+("#&($1%&!0&6%':'(0B'/')'*('(/.%+)+*()'(0'/')'()&(1&8M0$+*("#&(/+)$40':'/('*(&1%$-)')&*9(J**&('*6&0%+(6!+0#!':'(6+!(#/'('1+%';<+(1'(&1%$)')&(/+)$40')'("#&($1)$0':'("#'3(6G8$1'(&('(!&*6&0%$:'(!&8$<+("#&(6!&0$*':'(*&!('%#'3$D')'9(

L&!%'/&1%&(&**'(1<+(,+$('(*+3#;<+(/'$*(*$/63&*("#&(6+)&!$'(*&!(#%$3$D')'(1'"#&3&(/+/&1%+(6'!'(!&*+3:&!('("#&*%<+()+( f l(!&:&!*+5(6+!./(&**&(*&!:$;+()'('!"#$%&%#!'( ,+$( !&#%$3$D')+()&(#/'(,+!/'(/#$%+(,G0$3(&/(+#%!'*(,#10$+1'3$)')&*9(X(#*+()+( f l(!&:&!*+(1+(,!'/&-+!d(&*0+3B$)+(&!'(0+/63$0')+(&(&7$8$'(#/'(0#!:'()&('6!&1)$D')+(!'D+G:&35(&(8!';'*('(&**'(*+3#;<+(,+$(/#$%+(,G0$3()&(*&!($/63&/&1%')'(nas funcionalidades seguintes.

W<+(.(6+!"#&(*&(&*%G(#%$3$D'1)+(/.%+)+*(G8&$*("#&(%#)+(1'('!"#$%&%#!'(6!&0$*'(*&!(*$/63&*(&(,&$%+(apenas para as funcionalidades de agora. Quando se fala de arquitetura, o momento é o “mais respon-*G:&3H5("#&(6+)&(*&!(1+(0+/&;+()+(6!+K&%+9(J7$*%&(3#8'!(6'!'(*+3#;>&*(*+4*%$0')'*(&($1%&3$8&1%&*(*&($**+(,+!(/&3B+!'!(+(!&F*+(&('8$3$D'!('($/63&/&1%';<+()'*(6!M7$/'*(,#10$+1'3$)')&*9(C&**'(,+!/'5(*&('38#./(1'(&"#$6&(%&/('(:$*<+()&()&*&1:+3:&!('38+("#&(6+)&(*&!(!&#%$3$D')+(&($!G(*$/63$40'!(+(%!'='3B+()&(%+)+*5(6+!("#&(1<+I

Page 6: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

19 \

m&!'!)(P&D*'!+*("#&(/&(0B'/+#('%&1;<+()$D$'("#&()$,&!&1%&/&1%&( )+( 0M)$8+( )&( 6!+)#;<+( +( 0M)$8+( )&(%&*%&*(.(E+60$+1'3H(&('0'='(*&1)+(K+8')+(,+!'("#'1)+(#/'(/#)'1;'(/#$%+(%!'='3B+*'(.(1&0&**G!$'9(O+!($**+(é importante se atentar ao design do código de testes 6'!'("#&(#/'(/#)'1;'(1&0&**G!$'(6+**'(*&!(,&$%'(&/(apenas um local e não em diversos scripts.

e#'1)+(*&(0!$'(#/'('!"#$%&%#!'()&(%&*%&*5()&41&--se como devem ser os testes para classes que pos-suem o mesmo papel na arquitetura. Para estarem no mesmo local, provavelmente possuem várias coisas em comum como o fato de se comunicarem com ou-tras classes do mesmo tipo ou até mesmo implemen-tarem uma mesma interface. Isso gera uma grande oportunidade de reúso de código de teste! Pode-se 0!$'!(/+0d*( !&#%$3$DG:&$*5( ,#1;>&*( '#7$3$'!&*5( *#6&!-03'***&*()&(%&*%&(&('%.(/&*/+('1+%';>&*(6'!'(*&!&/(#%$3$D')'*( R:&!( ,!'/&-+!d( P'd& _&*%( 1'*( !&,&!`1-0$'*S9(U**+(0&!%'/&1%&($!G(*$/63$40'!('(0!$';<+()&(1+-:+*(%&*%&*(&(%+!1'!G('(/'1#%&1;<+()+*(%&*%&*(&7$*%&1-tes muito mais fácil! Observe que o mesmo que está *&1)+(,&$%+(6'!'('('!"#$%&%#!'()'('63$0';<+(%'/=./(se aplica à arquitetura de teste!

A#/'!$D'1)+5( &**'( '!"#$%&%#!'( )&( %&*%&*( *&!:$!G(como referência aos desenvolvedores do time a res-peito de como devem testar cada tipo de componen-te. Isso certamente ajuda muito os desenvolvedores "#&('$1)'(1<+(%`/(&76&!$`10$'(&/(%&*%&*9( 3./()$**+5(essa prática ajuda a validar se a arquitetura proposta ,+$()&41$)'()&(,+!/'(%&*%G:&3(&(6!+0#!'(8&!'!(0M)$8+(!&#%$3$DG:&3(%'/=./(6'!'(+*(%&*%&*N(

5367#*(,&4/ Classe abstrata para os testes de persis-tência.

public abstract class GenericDAOTest<E> extends DBTestCase { protected static 8-#9 String XML_PATH = “src/test/resources/data/”; protected GenericDAO<E> dao; protected EntityManager em; // Initialization methods public GenericDAOTest(String name) { super(name); System.setProperty( PropertiesBasedJdbcDatabaseTester. DBUNIT_DRIVER_CLASS,”jdbcDriverClass”); System.setProperty( PropertiesBasedJdbcDatabaseTester. DBUNIT_CONNECTION_URL,”conectionURL”); System.setProperty( PropertiesBasedJdbcDatabaseTester. DBUNIT_USERNAME, “unsername”); System.setProperty( PropertiesBasedJdbcDatabaseTester. DBUNIT_PASSWORD,”password”); System.setProperty( PropertiesBasedJdbcDatabaseTester. DBUNIT_SCHEMA,”schema”); } @Override protected IDataSet getDataSet() throws Exception { String setupFileName = getAnnotationValue(InitialDatasetFile.class). toString();

:(8-3;<%&!#&#$="37(7"$#&!(&7(67(6&!(&>($6367?-03#&0%,&@>AO!&*&10$&$(&**'(6!G%$0'(&/(#/(6!+K&%+("#&(#%$3$D':'(fO (1'(0'/')'()&(6&!*$*%`10$'(&(6+**#2'(#/(

C X(8&1.!$0+(6'!'('*(+6&!';>&*(=G*$0'*()&(L\?C9(W&**&(0'*+5(1'(:&!)')&5(+("#&(6!&0$*':'(*&!(%&*%')+(&!'(+(/'6&'/&1%+()'*(03'**&*9(L+/+('(,+!/'()&('0&**'!(+(C X(8&1.!$0+(&!'(*&/6!&('(/&*/'5(,+$(6+**2-:&3(0!$'!(#/'(03'**&('=*%!'%'()&(%&*%&*("#&(#%$3$D':'(+(Ci?1$%(6'!'(!&'3$D'!(&**&(%$6+()&(%&*%&9(J**'(03'**&(está apresentada na Listagem 1.

Observe que existem vários métodos abstratos que são chamados pelos métodos de teste, que só *&!<+()&41$)+*(1'(*#=03'**&9(J**&*(/.%+)+*(*<+(#%$3$D')+*(6'!'('*(6'!%&*()+(%&*%&("#&(*<+(&*6&0240'*(para cada classe que se deseja testar a persistência, como para recuperar a entidade para ser usada no %&*%&(+#(6'!'(:&!$40'!(*&('(&1%$)')&(!&0#6&!')'(&*%G(0+!!&%'9(J**'(6!G%$0'(.(0B'/')'()&(_&/63'%&(_&*%(&(.(&"#$:'3&1%&('+(6')!<+()+(m+^(_&/63'%&(P&%B+)9

Outra coisa interessante nessa classe abstrata é que ela recebe um tipo genérico, para que as sub-03'**&*()&41'/("#'3(+(%$6+(0+10!&%+("#&(&*%<+(%&*%'1)+("#'1)+('(&*%&1)&!&/9(X(/.%+)+('#7$3$'!(8&%-m&1&!$0L3'**RS(!&0#6&!'(6+!(!&g&7<+(&**'(03'**&(8&1.!$0'()&41$)'(&(!&%+!1'(6'!'(*&!(#%$3$D')'(&/('38#1*(%&*%&*9(n&K'/("#&('(6!M6!$'()&41$;<+()+(6'!T/&%!+(8&1.!$0+(6+)&(*&!(#/'(,+!/'()&()$,&!&10$'!(+(0+/-portamento de uma subclasse.

3./()'()&41$;<+()+(%$6+(8&1.!$0+(&()'($/63&/&1%';<+()+(/.%+)+('=*%!'%+5(+#%!'(,+!/'()'(*#=-03'**&(0+148#!'!(6'!T/&%!+*(/'$*(*$/63&*(6'!'(+(%&*%&(.(#*'1)+('1+%';>&*9(W&**&(0'*+5('*('1+%';>&*()&41&/(+(1+/&()+*('!"#$:+*(lPa(6'!'(+(Ci?1$%($1$0$'3$D'!('(='*&()&()')+*('1%&*()+(%&*%&(&(6'!'(0+/-6'!'!(0+/(+*(!&*#3%')+*('6M*('(0B'/')'()+(/.%+)+(%&*%')+9(X(/.%+)+(8&% 11+%'%$+1n'3#&RS('#7$3$'(nesse processo!

Page 7: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 20

return new FlatXmlDataSetBuilder().build( new FileInputStream(XML_PATH + setupFileName)); } @Override

public void setUp() throws Exception { super.setUp(); Map<String, String> persistenceProperties = new HashMap<String, String>(); persistenceProperties.put(“hibernate.connection.url”, “conectionURL”); persistenceProperties.put( “hibernate.connection.driver_class”, “jdbcDriverClass”); persistenceProperties.put( “hibernate.connection.password”, “password”); persistenceProperties.put( “hibernate.connection.username”, “username”); EntityManagerFactory emf = Persistence.createEntityManagerFactory( “punit_test”, persistenceProperties); em = emf.createEntityManager(); dao = new GenericDAO<E>(); dao.setEntityManager(em); } // Template test methods public void testGetBean() { E bean = dao.8-!BCD!(getIdForTest(), getGenericClass()); verifyRetrievedBean(bean); } public void testDeleteBean() throws Exception { em.getTransaction().begin(); dao.delete(getIdForTest(), getGenericClass()); em.getTransaction().commit(); String afterDeleteFileName = getAnnotationValue( AfterDeleteDatasetFile.class).toString(); compareTables(afterDeleteFileName); } public void testInsertNewBean() throws Exception { em.getTransaction().begin(); dao.save(retrieveBeanToBeInserted()); em.getTransaction().commit(); String afterInsertFileName = getAnnotationValue( AfterInsertDatasetFile.class).toString(); compareTables(afterInsertFileName); } public void testUpdateExistentBean() throws Exception { em.getTransaction().begin(); dao.save(retrieveBeanToBeUpdated()); em.getTransaction().commit(); String afterInsertFileName = getAnnotationValue( AfterUpdateDatasetFile.class).toString(); compareTables(afterInsertFileName); }

public void testListBeans() throws Exception { List<E> list = dao.list(getGenericClass()); verifyRetrievedList(list); }

// Abstract Methods protected abstract Object getIdForTest(); protected abstract void verifyRetrievedBean(E o); protected abstract E retrieveBeanToBeInserted(); protected abstract E retrieveBeanToBeUpdated(); protected abstract void verifyRetrievedList( List<E> list); // Helper methods protected Object getAnnotationValue(Class annotationType) throws Exception { Object anot = this.getClass().getAnnotation( annotationType); Method m = ((Annotation) anot).annotationType(). getMethod(“value”); return m.invoke(anot); } protected Class<E> getGenericClass() { Class<?> clazz = this.getClass(); while(clazz.getSuperclass() ! GenericDAOTest.class) { clazz = clazz.getSuperclass(); } ParameterizedType t = (ParameterizedType) clazz.getGenericSuperclass(); Type genericParam = t.getActualTypeArguments()[0]; return (Class<E>) genericParam; } protected void compareTables(String expectedDatasetFileName) throws Exception { IDataSet databaseDataSet = getConnection().createDataSet(); IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build( new FileInputStream(XML_PATH + expectedDatasetFileName)); String [] tableNames = (String []) getAnnotationValue(CompareTables.class); for (String tableName : tableNames) { ITable actualTable = databaseDataSet.getTable(tableName); ITable expectedTable = expectedDataSet.getTable(tableName); Assertion.assertEquals(actualTable, expectedTable); } } }

Page 8: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

21 \

(a$*%'8&/(j('6!&*&1%'(+(&7&/63+()&(#/'(03'**&(concreta de testes que estende a classe apresentada 1'(a$*%'8&/(Y9(\&6'!&("#&(+("#&(&3'(,'D(.(='*$0'/&1%&($/63&/&1%'!(+*(/.%+)+*('=*%!'%+*(&()&41$!('*('1+%'-;>&*9(X=:$'/&1%&(*&(/'$*('38#/(%&*%&(,+!(1&0&**G!$+5(%'/=./(6+)&(*&!()&41$)+(1&**'(03'**&N(

Listagem 2. Classe Concreta de Testes.

@InitialDatasetFile(“pessoa_dataset.xml”)@AfterDeleteDatasetFile(“afterdelete_pessoa_dataset.xml”)@AfterInsertDatasetFile(“afterinsert_pessoa_dataset.xml”)@AfterUpdateDatasetFile(“afterupdate_pessoa_dataset.xml”)@CompareTables(“pessoa”)public class PessoaDAOTest extends GenericDAOTest<Pessoa>{ public PessoaDAOTest(String name) { super(name); } @Override protected Object getIdForTest() { return “11111111111”; } @Override protected void verifyRetrievedBean(Pessoa p) { assertEquals(“Eduardo”, p.getNome()); assertEquals(“Guerra”, p.getSobrenome()); assertEquals(“M”, p.getSexo()); assertEquals(30, p.getIdade().intValue()); } @Override protected Pessoa retrieveBeanToBeInserted() { Pessoa p = new Pessoa(); p.setCpf(“44444444444”); p.setNome(“Fulano”); p.setSobrenome(“da Silva”); p.setIdade(40); p.setSexo(“M”); return p; } @Override protected Pessoa retrieveBeanToBeUpdated() { Pessoa p = new Pessoa(); p.setCpf(“11111111111”); p.setNome(“Eduardo”); p.setSobrenome(“War”); p.setIdade(31); p.setSexo(“M”); return p; } }}

@Override protected void verifyRetrievedList(List<Pessoa> list) { assertEquals(3, list.size()); List<String> ids = Arrays.asList( new String[]{“11111111111”,”22222222222”, “33333333333”}); for(Pessoa p : list){ assertTrue(ids.contains(p.getCpf())); }

!"#$%&'()*#(#++#(#,#-./'(%/*+&"0(1#-(!'-'(*-(1'-( $#+%23( $#( &#+&#+( .'$#( +%-./%4!0"( 0( !"%056'( $#(testes da arquitetura. Os desenvolvedores não preci-+0-(-0%+(!'342*"0"(#( /%$0"(!'-(0( 78($'(9:;3%&(0(cada teste, pois isso foi feito na superclasse. Por mais que dê certo trabalho criar a classe genérica para os testes, esse trabalho será compensado e muito com 0(02%/%$0$#()*#(+#"<($0$0(3'(&"010/='($#(!"%056'($#(testes para essa camada para cada classe persistida. É importante não confundir overdesign com um design inteligente e que permite ganho de produtividade!

Requisitos não-funcionais incrementais>6'(0$%03&0()*#"#"( %3!/*%"( 0( %-./#-#3&056'($#(

todos os requisitos não-funcionais da arquitetura /'2'(30(."%-#%"0(%&#"056'?(@++#(30(A#"$0$#(B(*-($'+(grandes problemas da abordagem tradicional para o $#+#3A'/A%-#3&'($0(0")*%&#&*"0C(4!0D+#(-*%&'(&#--po desenvolvendo funcionalidades relativas à infra-#+&"*&*"0($0(0./%!056'(#(36'(!'%+0+()*#(02"#20-(A0/'"(0'(!/%#3&#?(9#++0(E'"-0F($#.'%+($#(*-(1'-(&#-.'(%--plementando não se tinha nenhuma funcionalidade realmente que podia ser usada e validada pelo clien-te.

@++0+( 2"03$#+( E0+#+( $#( %-./#-#3&056'( E'!03$'(apenas em requisitos não-funcionais é que muitas A#G#+(!0*+0-('(!=0-0$'('A#"$#+%23F('*(H+'1"#D#3-2#3=0"%0I( $0( 0")*%&#&*"0?( @-( '*&"0+( .0/0A"0+F( %++'('!'""#()*03$'(+#(*&%/%G0(+'/*5J#+(-0%+(!'-./#,0+($'()*#(3#!#++<"%'F($#+.#"$%503$'(&#-.'(A0/%'+'($#($#-+#3A'/A%-#3&'?( /B-($%++'F(*-0(+'/*56'(-0%+(!'--plexa do que o necessário pode tornar o código mais complexo e mais difícil de se manter.

Essa prática sugere que os requisitos não-funcio-30%+()*#(+#("#E#"#-(0(+#"A%5'+()*#(0(0")*%&#&*"0(."'AK(.0"0(0(0./%!056'F(+#L0-(%3!/*M$'+(0'+(.'*!'($*"03&#(0+( %&#"05J#+?( N1A%0-#3&#( $#A#D+#( !'-#50"( !'-( '+(que possuem maior prioridade para o negócio e um -0%'"( "%+!'( &B!3%!'?( ( 2"03$#( $%E#"#350( 0)*%( B( )*#(%++'( A0%( +#3$'( E#%&'( %3!/*%3$'(;+#"( O&'"%#+( 0")*%&#-&*"0/-#3&#(+%23%4!0&%A0+($#(E'"-0(2"0$*0/(30+(%&#"0-5J#+?(7'"(H0")*%&#&*"0/-#3&#I(+%23%4!0&%A0+(#3&#3$#--se as histórias que exploram uma parte importante da arquitetura.

8-./#-#3&03$'(#++#+(+#"A%5'+($0(0")*%&#&*"0(E'-cados em uma funcionalidade, é possível implemen-

Page 9: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 22

tar o que realmente é necessário para ela, evitando a %3+#"56'($#(!'%+0+()*#(3*3!0(+#"6'(*&%/%G0$0+?(9#A#--se trabalhar nas funcionalidades da arquitetura fo-cando sempre em necessidades concretas e que são 3#!#++<"%0+(02'"0F(!'-'(.0"0(;+#"(O&'"%#+($0(%&#"056'(0&*0/?(8++'(#A%&0(#+.#!*/05J#+($'(&%.'C(I7'$#(+#"()*#(*-($%0(%"#-'+(."#!%+0"($%++'PI?(

7'"('*&"'(/0$'F(B(%-.'"&03&#(!"%0"(#++#+(+#"A%5'+(0")*%&#&*"0%+($#(E'"-0(E<!%/($#(+#"#-("#*&%/%G0$'+(#-('*&"0+(E*3!%'30/%$0$#+?(Q0-'+(%/*+&"0"(*+03$'(!'-'(exemplo uma funcionalidade de controle de acesso. 8-02%3#()*#(30(&#"!#%"0(%&#"056'($#(*-(."'L#&'($#!%-de-se implementar o controle de acesso em uma fun-!%'30/%$0$#('3$#( %++'(B(-*%&'( %-.'"&03&#?(>0( %$#%0($#(E0G#"(&*$'($0(E'"-0(-0%+(+%-./#+F(%++'(.'$#"%0(+#"(%3!/*M$'(!'-'(*-0(A#"%4!056'(H=0"$D!'$#$I(3'(-#%'(do corpo de um método. Porém todos sabem que o

Como embutir novos requisitos não-funcionais em uma arquiteturaR*%&'+($'+("#)*%+%&'+(36'DE*3!%'30%+("#."#+#3&0-(!0"0!&#"M+&%!0+(&"03+A#"+0%+($'(+%+&#-0F('*(+#L0F(

)*#(!'"&0-(&'$0(0(#+&"*&*"0($#(E*3!%'30/%$0$#+?(8++'(+%23%4!0()*#(#++0+()*#+&J#+F(!'-'(+#2*"0350(#(/'22%32F(#+&0"6'(."#+#3&#+(#-($%A#"+0+(E*3!%'30/%$0$#+($'(+%+&#-0?(70"0(.#"-%&%"()*#(0(%-./#-#3&056'(dos interesses transversais possa acontecer em paralelo e de forma independente das funcionalidades, #/#+($#A#-(#+&0"($#(0/2*-0(E'"-0(-'$*/0"%G0$'+?

;-(.0$"6'($#(."'L#&'()*#(3'+(.#"-%&#(0$%!%'30"(3'A0+(E*3!%'30/%$0$#+(#-(*-0(!/0++#(#,%+&#3&#(B('(9#!'"0&'"?(@++0(!/0++#(E*3!%'30(!'-'(*-(."',S()*#(%-./#-#3&0(0(-#+-0(%3&#"E0!#($0(."T."%0(!/0++#?(N(9#!'"0&'"($#/#20(0(E*3!%'30/%$0$#(.0"0(0(!/0++#('"%2%30/F(#,#!*&03$'(0(E*3!%'30/%$0$#(0$%!%'30/(03&#+('*($#.'%+?(O#(0+(!/0++#+()*#()*#"(#3!0.+*/0"(.'++*#-(&'$0+(0(-#+-0(%3&#"E0!#F(0(+%-./#+(0./%!056'($'(.0$"6'($#A#(+#"(+*4!%#3&#F(.'"B-()*03$'(#,%+&#-(A<"%0+(%3&#"E0!#+(B(3#!#++<"%'(0.#/0"(U( 78($#("#V#-,6'(#(*&%/%G0"(."',S+($%3W-%!'+?(9#()*0/)*#"(E'"-0F(.0"0(#++0(#+&"0&B2%0(.'$#"(+#"(*&%/%G0$0F(B(."#!%+'(&#"(!'3&"'/#($'(-'-#3&'($0(!"%056'($'('1L#&'F(!'-'(!'-('(*+'($#(*-0(E<1"%!0F(.'"(#,#-./'?( ++%-(B(.'++MA#/("#&'"30"('('1L#&'(#3!0.+*/0$'(!'-('(9#!'"0&'"F(0'(%3AB+($'('1L#&'('"%2%30/P

N*&"0(0/&#"30&%A0(3#++#+(!0+'+(B('(*+'($#(!'-.'3#3&#+()*#(.'$#-(%3&#"!#.&0"(0(#,#!*56'($#(E*3-!%'30/%$0$#+?( ( 78($#(O#"A/#&+F(.'"(#,#-./'F(.'++*%('+(O#"A/#&(X%/&#"+()*#(.'$#-(+#"(*&%/%G0$'+(.0&0(#,#!*&0"(E*3!%'30/%$0$#+(03&#+('*($#.'%+($#(*-0("#)*%+%56'(YZZ7(0'(+#"A%$'"?(N(@[:(0(.0"&%"($0(A#"+6'(\(#(0(3'A0( 78(]98(.'++*#-('+(%3&#"!#.&'"#+F()*#(.'$#-(+#"(*&%/%G0$'+(.0&0(%3&#"!#.&0"(0(!=0-0$0($#(-B&'$'+(30+(!/0++#+(!'3&"'/0$0+(.#/'(!'3&0%3#"?( &B(-#+-'(0( 78($#(.#"+%+&K3!%0(!'-'('([7 (.'++*%(os listeners, que são chamados quando determinados eventos ocorrem no momento de persistir ou "#!*.#"0"(*-0(#3&%$0$#?(Z'$'+(#++#+(!'-.'3#3&#+(.'$#-(+#"(*&%/%G0$'+(.0"0(0$%!%'30"(3'A'+(!'-.'"-tamentos em funcionalidades já existentes de forma transparente.

Finalmente, não poderia me esquecer dos aspectos que foram tema dos meus dois últimos artigos .0"0(0("#A%+&0P(@/#+(+6'(-T$*/'+(!*L'('1L#&%A'(B(L*+&0-#3&#(0(+#.0"056'($#++#+(%3&#"#++#+(&"03+A#"+0%+($'("#+&'($0(0./%!056'?(O#(+*0(0./%!056'(*&%/%G0('(O."%32F(#/#(L<(A#-(."#.0"0$'(.0"0('(*+'($#(0+.#!&'+(#-(&#-.'($#(#,#!*56'(0(.0"&%"($0(+%3&0,#($#(03'&05J#+($'( +.#!&[?(O#(A'!K(36'('(*&%/%G0F('( +.#!&[(0%3$0(.#"-%&#()*#('+(0+.#!&'+(+#L0-(!'-1%30$'+(!'-(0(0./%!056'(3'(-'-#3&'($0(!'-.%/056'('*($'(!0""#20-mento das classes pela máquina virtual.

R*%&0+(A#G#+(#++0+(E*3!%'30/%$0$#+(."#!%+0-(+#"(!'342*"0$0+(#(+6'(/%2#%"0-#3&#($%E#"#3&#+(.0"0(!0$0(-B&'$'(%3A'!0$'?(>'(!0+'($'(!'3&"'/#($#(0!#++'F(B(."#!%+'(&#"(0(%3E'"-056'($#()*#-(&#-(0*&'"%-G056'(.0"0(0)*#/0(E*3!%'30/%$0$#?(>#++#(!0+'F(*-0(+0M$0(B(*&%/%G0"(-#&0$0$'+(0$%!%'30%+(30(E'"-0($#(03'&05J#+F(0"-0G#30$'+(#-($'!*-#3&'+(^R_('*(3'(103!'($#($0$'+?( (.0"&%"($#++0+(!'342*"05J#+F(#++#+(-T$*/'+(&K-(%3E'"-056'(+*4!%#3&#(.0"0(+01#"(!'-'(0(E*3!%'30/%$0$#(."#!%+0"<(+#"(#,#!*&0$0?

83$#.#3$#3&#-#3&#($0(#+&"0&B2%0(*&%/%G0$0F(0(+#.0"056'($#++#+(%3&#"#++#+($#%,0('(!T$%2'(E*3!%'30/(-0%+(/%-.'F(-0%+(E<!%/($#(+#"("#*&%/%G0$'(#(-0%+(E<!%/($#(+#"(&#+&0$'?( /B-($%++'F(%++'(.#"-%&#(0(#A'/*56'($'+(+#"A%5'+($0(0")*%&#&*"0($#(E'"-0(%3$#.#3$#3&#($'("#+&'($0(0./%!056'?

!"#$%&'(&Representação da Landing Zone.

LANDING ZONE

mínimo alvo excelente

Page 10: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

23 \

controle de acesso precisará ser feito para todas as funcionalidades e essa abordagem geraria retrabalho. Sendo assim, apesar do foco ser nos requisitos atuais de controle de acesso, deve-se tentar isolar a funcio-30/%$0$#($#(E'"-0(0(#/0(.'$#"(+#"("#*&%/%G0$0?(>#++#(!0+'F(.'$#"%0( +#"(*&%/%G0$'(0/2'( !'-'(*-(4/&"'F(*-(%3&#"!#.&'"('*(*-(."',S(`A#"()*0$"'a?

;-( +#"A%5'( $0( 0")*%&#&*"0( 36'( ."#!%+0( #-( +*0(primeira versão já atender a todos os requisitos pos-+MA#%+?(@/#(.'$#(!'-#50"(+%-./#+F(0&#3$#3$'(0(3#!#+-sidade do momento, e depois ir evoluindo aos poucos. O isolamento dessa funcionalidade do resto da apli-!056'(.#"-%&#()*#(#/0(.'++0(+#"(0/&#"0$0(E0!%/-#3&#F(sem impactar em diversos pontos do código, caracte-"%G03$'('(10$(+-#//(O='&2*3(O*"2#"S?(N(*+'($#(&#+&#+(de unidade ajuda a garantir que o caso mais simples !'3&%3*0(E*3!%'303$'(!'-(0$%56'($#(!'-.'"&0-#3-&'+(-0%+(+'4+&%!0$'+?

b(."#!%+'($#%,0"(1#-(!/0"'()*#($#%,0"(#+.05'(.0"0(que os requisitos não-funcionais possam ser incluí-dos e evoluídos aos poucos é diferente de querer im-./#-#3&0"( &'$'+($#(*-0(A#G?(c*03$'(0( 0")*%&#&*"0(é elaborada, é importante que já exista um plano de como essas novas funcionalidades que afetam toda 0./%!056'(.'$#"6'(+#"( %3!/*M$0+($#(E'"-0(%+'/0$0($0(parte funcional do sistema. É diferente criar um de-sign especulativo, no qual se inclui coisas que não sabe se eram necessárias, de um design responsável, na qual se inclui pontos de extensão nos locais certos para que a arquitetura tenha a capacidade de evoluir. O01#"(0($%E#"#350(#3&"#('+($'%+(36'(B(0/2'(&"%A%0/(#()*#(A#-($0(#,.#"%K3!%0($'+(-#-1"'+($'(&%-#?(X#/%G-#3-&#(#""0"(B(.#"-%&%$'(#(0("#E0&'"056'(#,%+&#(#,0&0-#3&#(.0"0(#/%-%30"(+'/*5J#+($#+3#!#++<"%0+(#(#A'/*%"(.0"0(novas estruturas.

Landing Zones (ou Zonas de Pouso)Existem algumas características não-funcionais

$#( *-0( 0")*%&#&*"0( )*#( 36'( +6'( +#"A%5'+( )*#( !0$0(*-0($0+(E*3!%'30/%$0$#+(%"<(*&%/%G0"?(;-(1'-(#,#--plo é desempenho! O tempo que um software demora para ser executado ou a memória que ele consome +6'( !'3+#)*K3!%0( $#( +*0( %-./#-#3&056'( !'-'( *-(todo. Outras características não-funcionais como carga, disponibilidade e, em alguns casos, portabi-lidade também entram nessa categoria. Quando se $#A#(&"010/=0"(30(0")*%&#&*"0($0(0./%!056'(.0"0(-#-/='"0"( *-0( $#++0+( !0"0!&#"M+&%!0+d(c*03$'( #/0( #+&<(1'0('(+*4!%#3&#d

Z%A#(0('.'"&*3%$0$#($#(0++%+&%"(0(.0/#+&"0($0(e#-1#!!0(f%"E+D:"'!g(3'( 2%/#(7'"&*20/($#+&#(03'F('3$#(#/0( %3&"'$*G%*(*-(!'3!#%&'(-*%&'( %3&#"#++03&#(!=0--0$'(_03$%32(h'3#(`'*(h'30($#(7'*+'a?(@-(*-(+'E-&i0"#(!'-./#,'F(B( !'-./%!0$'($#43%"()*#(*-(A0/'"(ótimo para uma determinada característica, princi-.0/-#3&#( .'")*#( -*%&0+( A#G#+( B( ."#!%+'( 10/03!#0"(

essas características para se chegar a um resultado 0$#)*0$'?( ( _03$%32( h'3#( B( *-( %3&#"A0/'( $#( *-0(característica mensurável do sistema apresentando )*0%+(+6'('+(A0/'"#+(0!#%&<A#%+(.0"0('(-#+-'?( (42*"0(j(0."#+#3&0(2"04!0-#3&#(0(%$#%0($'(!'3!#%&'?

;-0(E'"-0(+%-./#+($#(+#("#."#+#3&0"(*-0(_03-ding Zone é através de uma tabela. Essa tabela possui uma coluna contendo o valor alvo para o valor da me-$%56'F(*-(A0/'"()*#(+#"%0(#,!#.!%'30/(#('*&"0()*#(+#-ria o limite mínimo aceitável. Cada linha representa *-(0&"%1*&'($%E#"#3&#()*#($#A#(+#"(-#$%$'?(>'(!0+'(de valores que precisam ser medidos manualmente, o %$#0/(B()*#(0(-#$%56'(+#L0(E#%&0(.#/'(-#3'+(*-0(A#G(0'(430/($#(!0$0(%&#"056'F(.0"0(+01#"(+#(+#"<(3#!#++<-rio incluir alguma atividade de ajuste da arquitetura .0"0( 0( %&#"056'( +#2*%3&#?( /2*-0+(-#$%5J#+(.'$#-(+#"('1&%$0+($#(E'"-0(0*&'-0&%G0$0F($#(E'"-0(0(.'$#-rem ser executadas em períodos mais curtos, como a cada dia ou a cada build.

(&01#/0(k(0."#+#3&0(*-(#,#-./'($#(*-0(&01#/0(!'-(0($#43%56'($#(_03$%32(h'3#+(.0"0('($#+#-.#-nho e a carga do sistema de relatórios que está sen-$'(*+0$'(!'-'(#,#-./'(3#+&#(0"&%2'?(>'&#()*#(3#-(+#-."#('(A0/'"(0/A'(4!0(#,0&0-#3&#(30(-#&0$#(#3&"#('(/%-%&#(#('(#,!#/#3&#?(>'(!0+'($'(&#-.'($#(."'!#+-+0-#3&'($#(*-("#/0&T"%'('(A0/'"(0/A'(B(\l(-%3*&'+F(sendo que o valor limite é o dobro, uma hora. O valor #,!#/#3&#(L<(B($#(*-(-%3*&'F(\l(A#G#+(-#3'+($'()*#(o alvo. Em alguns casos, pode ser que o valor limite e '(0/A'(+#L0-(%2*0%+F(!0"0!&#"%G03$'(*-0(+%&*056'(#-(que o valor desejado já é o limite mínimo para aquele atributo.

Landing Zones para Qualidade de Código

Requisitos para qualidade de código são atributos que podem ser incluídos dentro de *-0( _03$%32( h'3#( $'( +%+&#-0?( ( .0"&%"( $#-les pode-se monitorar continuamente como anda a qualidade de cada módulo do sistema #("#0/%G0"(0+($#A%$0+("#E0&'"05J#+()*03$'(3#-!#++<"%'?( X#""0-#3&0+( .0"0( %3+.#56'( #( !'3-trole contínuo de código que podem ser uti-/%G0$0+(.0"0('(!'3&"'/#($#++#(&%.'($#(_03$%32(h'3#?( ;-( 1'-( #,#-./'( $#( *-0( E#""0-#3&0(desse tipo é o Sonar, que foi apresentado com -0%'"#+($#&0/=#+(3'(0"&%2'(H@A'/*%3$'(9#+%23(#( ")*%&#&*"0( &"0AB+($0+(RB&"%!0+($'(O'30"I($0(#$%56'(m\($0("#A%+&0?

Page 11: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 24

Atributo Limite Alvo ExcelenteTempo para solicitar um novo relatório

kl+ \+ kll-+

Tempo de espera para o processamento de um relatório

1 hora \l(-%3 1 minuto

Relatórios processados por hora

klll nlll kllll

Tabela 1. Exemplo de Landing Zones para a aplicação-exemplo.

É muito importante que em um ambiente ágil a equipe saiba adaptar e ajustar seus Landing Zones com o tempo. À medida que se segue em um projeto, A0%D+#(0-0$*"#!#3$'(#-("#/056'(0()*0%+(+6'('+("#0%+(/%-%&#+($0(0./%!056'(3'(!'3&#,&'($#(3#2T!%'($'(!/%#3-te. Pode ser que um valor que parecia não ser aceitá-vel a princípio, seja aceitável em troca de um ganho em outro requisito. Imagine dentro do exemplo apre-sentado que a princípio não seja aceitável que um re-latório demore mais de uma hora para ser processado, porém que para se atingir isso não se consegue pro-cessar os mil relatórios em uma hora. Conversando com o cliente, chegou-se a conclusão que o tempo de "#+.'+&0(B(-0%+(%-.'"&03&#()*#(0()*03&%$0$#?(9#++0(E'"-0F(.'$#D+#(E0G#"(*-(0L*+&#(3'+(_03$%32(h'3#+($#(0!'"$'(!'-(#++0(3'A0(%3E'"-056'?

Os Landing Zones devem ser gerenciáveis e re-V#&%"#-( '+( 0&"%1*&'+( -0%+( %-.'"&03&#+( $'( +%+&#-0?(;-0()*03&%$0$#(-*%&'(2"03$#($#(0&"%1*&'+(.0"0(+#-rem medidos e acompanhados podem tirar o foco e 0(02%/%$0$#($0(#)*%.#?(>'(!0+'($#("#0/-#3&#(=0A#"(0(necessidade de monitorar um número grande de atri-butos, sugere-se que sejam divididos em categorias e que a forma de colher as métricas seja a mais auto--0&%G0$0(.'++MA#/?(

;-($'+( 2"03$#+( '1L#&%A'+( $0+( _03$%32(h'3#+( B(+#"A%"(!'-'(-'&%A056'(.0"0(0+("#E0&'"05J#+(0")*%&#-&*"0%+?( (#,%+&K3!%0($#(*-(/%-%&#(%3%1#('(.#"E#!!%'3%+-mo de querer deixar o sistema sempre melhor sem que isso agregue realmente valor ao negócio do clien-te. Por outro lado, quando um atributo ultrapassa ou chega próximo do valor mínimo, isso demonstra que 30(."T,%-0( %&#"056'($#A#D+#( "#E0&'"0"(0(0")*%&#&*"0(para melhorar aquele atributo. Observe que mesmo se tratando de requisitos técnicos, eles estão sendo trabalhados dentro das necessidades do cliente e as "#E0&'"05J#+( 30( 0")*%&#&*"0( 0!'3&#!#-()*03$'( #/0+(irão agregar valor ao negócio.

Imagine, por exemplo, que no estudo de caso descrito neste artigo o número de relatórios proces-+0$'+(.'"(='"0(#+&#L0(010%,'($#(-%/F()*#(4!0(E'"0($'(Landing Zone estipulado para esse atributo. Seria

L*+&%4!<A#/( )*#( 30( %&#"056'( +#2*%3&#( E'++#( %3+#"%$0(*-0(&0"#E0()*#(A%+0"%0(&"0G#"(#++#(A0/'"($#(A'/&0(.0"0($#3&"'($0("#2%6'(0!#%&<A#/?(>'(#,#-./'F(+#"%0(.'++M-vel criar uma forma de distribuir esse processamento .0"0(-0%+($#(*-0(-<)*%30F(A%01%/%G03$'('(."'!#++0-mento de um maior número de relatórios.

Para quem se interessar, o blog da Rebecca Wirfs-D:"'!g(`A#"("#E#"K3!%0+a(!'3&B-(-0%+(-0&#"%0/(0("#+-peito do uso de Landing Zones para equipes ágeis.

Refatorações arquiteturais .#+0"($0+(."<&%!0+(0."#+#3&0$0+(&#3&0"#-(03&#-

!%.0"(0+($#!%+J#+(0")*%&#&*"0%+($#(-0%'"("%+!'(#(A0/%-$<D/0+(30(."<&%!0F(-*%&0+(A#G#+(0(0")*%&#&*"0(0$'&0$0(acaba não sendo adequada para o sistema em ques-&6'?(R*%&0+(A#G#+F(#,%+&#-(-*$0350+($#("#)*%+%&'+("#-ferente ao negócio do cliente que possuem um gran-de impacto na arquitetura. Como exemplo podemos citar sistemas que operavam localmente e precisam operar remotamente, sistemas cujo número de usu-<"%'+(!"#+!#*($#(E'"-0(%3#+.#"0$0(#&!?(N*&"0+(A#G#+(não são propriamente os requisitos que mudam, mas B(0(+'/*56'(0$'&0$0(%3%!%0/-#3&#()*#(36'(+#(-'+&"0(adequada. Quando, por exemplo, as classes de uma !0-0$0(!'-#50-(0(4!0"(!'-(-*%&0+("#+.'3+01%/%$0-des, isso pode indicar a necessidade de uma camada 0$%!%'30/?(@-()*0/)*#"($#++#+(!0+'+F(!'-'($%G('(-0-3%E#+&'(<2%/F(B(."#!%+'(+#(0$0.&0"(U+(-*$0350+P

O#2*3$'(X'i/#"F(0("#E0&'"056'(B(*-0(&B!3%!0(#-(que se altera a estrutura interna de um software sem alterar seu comportamento externo. Porém, da forma !'-'(B($#43%$0F(0("#E0&'"056'(&"010/=0(!'-(.#)*#-30+(.'"5J#+($#(!T$%2'?(9#3&"'($#(*-0(0./%!056'F(.'-$#-'+($%G#"()*#(0("#E0&'"056'($#(!T$%2'(.'++*%(*-(efeito positivo na qualidade do código, mas que pos-sui um escopo local, impactando apenas nas classes onde foi aplicada.

( "#E0&'"056'( 0")*%&#&*"0/( B( *-( &%.'( $#( "#E0&'-"056'( -0%+( 0-./0( )*#( .'++*%( %-.0!&'( #-( &'$'( '(+%+&#-0?( @/0( 0/&#"0F( .'"( #,#-./'F( 0+( "#/05J#+( #3&"#('+(+*1+%+&#-0+(#(0($%A%+6'($#(!0-0$0+($0(0./%!056'?(@/0+(.'++*#-(*-(%-.0!&'(-0%+(+%23%4!0&%A'(#-(&'$0(0./%!056'($'()*#(0+("#E0&'"05J#+($#(!T$%2'DE'3&#F()*#(possuem um impacto mais local. Exemplos de refa-&'"05J#+(0")*%&#&*"0%+(+#"%0-C('($#+0!'./0-#3&'($#(*-0(E*3!%'30/%$0$#F(0(!"%056'($#(*-0(3'A0(!0-0$0('*(0(!"%056'($#(*-0("#+&"%56'($#(0!#++'(#3&"#(+*1+%+-temas.

90(-#+-0( E'"-0( )*#( 0( "#E0&'"056'( $#( !T$%2'-DE'3&#F(0("#E0&'"056'(0")*%&#&*"0/(&0-1B-(."#!%+0($#(&#+&#+(0*&'-0&%G0$'+(.0"0(A0/%$0"()*#(0+(0/&#"05J#+("#0/%G0$0+( 36'( -'$%4!0"0-( '( !'-.'"&0-#3&'( #,-&#"3'?( ]'-'( '( #+!'.'( $0+( "#E0&'"05J#+( B( $%E#"#3&#F('(&%.'($#(&#+&#(*&%/%G0$'(&0-1B-($#A#(+#"?(@3)*03&'(*+0-'+( &#+&#+( $#(*3%$0$#(.0"0( A0/%$0"( "#E0&'"05J#+($#( !T$%2'F( .0"0( 0+( "#E0&'"05J#+( 0")*%&#&*"0%+( +#"6'(

Page 12: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

25 \

Código repetitivo, mas não duplicado;-($'+(."%3!%.0%+(#(-0%+(T1A%'+(H-0*(!=#%"'+I()*#(.'$#-(=0A#"(#-(*-(+'E&i0"#(B(0($*./%!056'(

$#(!T$%2'?(8++'(E0G(!'-()*#(0(-03*&#356'($0(0./%!056'(+#L0(-0%+($%EM!%/(#(%3&"'$*G(0(.'++%1%/%$0$#($#(1*2+F($#A%$'(0(0/&#"056'(#-(0.#30+(.0"&#($'(!T$%2'($*./%!0$'?(7'"B-(#,%+&#('*&"'(&%.'($#(!T$%2'()*#(não é exatamente duplicado, mas que é repetitivo. Esse mau cheiro pode parecer inofensivo quando '/=0-'+(*-0(.#)*#30(.'"56'($#(!T$%2'F(-0+(#-(*-(0")*%&#&*"0(.'$#(2#"0"(E0/&0($#(V#,%1%/%$0$#(`.'%+(#++#(&%.'($#(!T$%2'(B(3'"-0/-#3&#(0!'./0$'(0'+('1L#&'+(!'-('+()*0%+(/%$0a(#(0E#&0"(3#20&%A0-#3&#(0(produtividade da equipe.

N(!T$%2'("#.#&%&%A'(B(0)*#/#()*#(E0G(0(-#+-0(!'%+0F(.'"B-(!'-('1L#&'+($%E#"#3&#+?(]'-'(#,#-./'($#(!T$%2'("#.#&%&%A'(.'$#"%0(!%&0"C("#!*.#"0"('+(A0/'"#+($'+(.0"W-#&"'+(YZZ7(#(!'/'!0"(#-(*-('1L#&'F("#!*.#"0"('+(A0/'"#+($'+(0&"%1*&'+($#(*-('1L#&'(.0"0(A0/%$<D/'+F("#0/%G0"(0('"$#3056'($#(*-0(/%+&0($#('1L#&'+(.'"(*-(!'3L*3&'($#(0&"%1*&'+(#+.#!M4!'+(#&!?( '(!"%0"(#++#(&%.'($#(!T$%2'F(0(#)*%.#(+#(AK(E0G#3$'(0(-#+-0(!'%+0(A<"%0+(A#G#+F(.'"B-(/%$03$'(!'-('1L#&'+($%E#"#3&#+?

;-0( "#E0&'"056'(0")*%&#&*"0/(.'++MA#/(.0"0( #/%-%30"( #++0( "#.#&%56'( B( 0( !"%056'($#( !'-.'3#3&#+()*#(*&%/%G0-("#V#,6'?( &"0AB+($0("#V#,6'(B(.'++MA#/(%$#3&%4!0"('()*#(B(!'-*-(3'(!T$%2'("#.#&%&%A'(#(0!#++0"($%30-%!0-#3&#(0+(."'."%#$0$#+($'('1L#&'F(&'"303$'(.'++MA#/(0(!"%056'($#(*-(o3%!'(!T$%2'()*#(.'$#(+#"(*+0$'(#-(&'$'+(+T(!0+'+?(]0+'(#,%+&0-($%E#"#350+(#3&"#('+(!T$%2'+("#.#&%$'+F(0+(03'&05J#+(+6'(*-0(E'"-0($#(.0"0-#&"%G0"(#++#(0/2'"%&-'($#(0!'"$'(!'-(0(!/0++#(*&%/%G0$0?

]'-'(#,#-./'("#0/F(*-0(A#G(-#($#.0"#%(!'-(*-(+%+&#-0()*#(.'++*M0($%A#"+0+(!/0++#+()*#(%-./#-mentavam a interface Comparator para ordenar uma lista de acordo com algum propriedade de um ob-L#&'?( ()*03&%$0$#($#++0+(!/0++#+(%0(!0$0(A#G(0*-#3&03$'(-0%+(#(#-(0/2*-0+(A#G#+(#"0(3#!#++<"%'(!"%0"(mais de uma para a mesma classe. O código em si não era duplicado, mas muito parecido. Como forma $#(#/%-%30"(#++0("#.#&%56'(E'%(!"%0$'(*-(!'-.0"0&'"(2#3B"%!'F(!'-'('($#-'3+&"0$'(30(_%+&02#-(\F()*#(*+0A0("#V#,6'(.0"0("#!*.#"0"(0(."'."%#$0$#(0(+#"(*+0$0(30('"$#3056'?(N+('*&"'+(!'-.0"0$'"#+(E'"0-(#,!/*M$'+(#(+*1+&%&*M$'+(.'"(#++#?( .#+0"($#(=0A#"(*-0(.#)*#30(.#"$0($#($#+#-.#3='F(#/0(E'%(0!#%&<A#/(#-("#/056'(0'(!'3&#,&'(2#"0/($0(0./%!056'?

)!*+%",-&.( Classe que realiza a comparação de dois objetos por uma propriedade(

public class !"#"$%&'()'*+,-,%'-./0 implements Comparator<E>{ private String comparisonField; private int order; public /0%1 static int ASCENDING = 1; public /0%1 static int DESCENDING = -1; public 2,3,4+!5065-7%$%+5$(String comparisonField, int order) { super(); this.comparisonField = comparisonField; this.order = order; } @Override @SuppressWarnings(“unchecked”) public int compare(E obj1, E obj2) { Object value1 = getProperty(obj1, comparisonField); Object value2 = getProperty(obj2, comparisonField); if(value1 == null){ if(value2 == null) return 0; else return order * -1;

}else if(value2 == null){ return order; }else if(value1 instanceof Comparable){ return order * ((Comparable)value1). compareTo(value2); }else{ return order * value1.toString().compareTo( value2.toString()); } } private Object getProperty(Object bean, String property) { String getterName = “get” + propertieName.substring(0, 1).toUpperCase() + propertieName.substring(1); try { Method method = bean.getClass().getMethod( getterName); return method.invoke(bean, new Object [] {}); } catch (Exception e) { throw new RuntimeException(“Can’t get property “ + property + “ in the class “ + bean.getClass().getName(), e); } } }

Page 13: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

/ 26

3#!#++<"%'+(&#+&#+(E*3!%'30%+('*(&#+&#+($#(%3&#2"056'?(;-0( "#E0&'"056'( )*#( 0$%!%'30"( *-0( 3'A0( !0-0$0(precisará que os testes funcionais validem se o com-.'"&0-#3&'(2#"0/($0(0./%!056'(.#"-03#!#*('(-#+-'?(@-('*&"0("#E0&'"056'()*#(0/&#"0"(0("#/056'(#3&"#($'%+(+*1+%+&#-0+F( *-( &#+&#( $#( %3&#2"056'( #3&"#( #/#+( +#-"%0(+*4!%#3&#?(N(&%.'($#(&#+&#(*&%/%G0$'(A0%($#.#3$#"(-*%&'($'(#+!'.'($0("#E0&'"056'?

90(-#+-0(E'"-0()*#(0("#E0&'"056'($#(!T$%2'F(0(

"#E0&'"056'(0")*%&#&*"0/($#A#(+#"(E#%&0(#-(.#)*#3'+(%3!"#-#3&'+?(7'"(#++#(-'&%A'F(#/0(0!010(-*%&0+(A#G#+(+#3$'(!'-.'+&0(.'"($%A#"+0+("#E0&'"05J#+($#(!T$%2'(mais granulares até se chegar a um resultado com %-.0!&'(#-(&'$0(0(0./%!056'?( (!0$0(.#)*#3'(.0++'($0( "#E0&'"056'(B( %-.'"&03&#( "'$0"('+( &#+&#+(.0"0( +#(!#"&%4!0"()*#(0&B(0)*#/#(.'3&'('(!'-.'"&0-#3&'(+#(manteve.

+(_03$%32(h'3#+(.'$#-(+#"(*&%/%G0$0+(.0"0($#-&#!&0"( 0( 3#!#++%$0$#( $#( "#E0&'"05J#+( 0")*%&#&*"0%+?(c*03$'(*-(0&"%1*&'($'(+%+&#-0(!'-#50(0(+0%"($'+(/%-mites do Landing Zone, é o momento de planejar uma 0&%A%$0$#(.0"0(E0G#"(!'-()*#('(A0/'"($0)*#/#(0&"%1*&'(A'/&#(.0"0(*-(A0/'"($#+#L<A#/?(c*03$'(+#(*&%/%G0(-B-&'$'+(<2#%+F($#A#D+#(."'!*"0"(E'!0"(#-()*#+&J#+()*#(são importantes para o cliente e que agregam valor .0"0( '( 3#2T!%'?( Z#'"%!0-#3&#F( 4!0"( &"010/=03$'( 30(-#/='"%0($'($#+#-.#3='($0(0./%!056'(B(0/2'()*#(0(princípio não agrega valor ao negócio e por isso essas 0&%A%$0$#+(0")*%&#&*"0%+(-*%&0+(A#G#+(+6'($#%,0$0+($#(lado. Com as Landing Zones é possível detectar o mo--#3&'(#-()*#(0)*#/#(#+E'"5'(.0"0(-#/='"0"(*-0(!0-racterística não-funcional do sistema realmente tem *-(%-.0!&'(+%23%4!0&%A'(.0"0('(3#2T!%'?

+("#E0&'"05J#+(0")*%&#&*"0%+(&0-1B-(.'$#-(E'"-3#!#"(*-(E##$10!g(#-("#/056'(0+(_03$%32(h'3#+($#-43%$0+?( '(+#("#E0&'"0"(0(0")*%&#&*"0F(-*%&0+(A#G#+(+#(E0G(&"'!0+()*#(-#/='"0-(*-(0&"%1*&'(#(.%'"0-('*&"'?( (!"%056'($#(*-(!0!=#F(.'"(#,#-./'F(.'$#(-#/='"0"(o tempo de resposta, mas irá aumentar a quantida-$#($#(-#-T"%0(!'3+*-%$0?( (.0"&%"($0+("#E0&'"05J#+F(pode-se ir repensando os limites dos Landing Zones $#43%$'+F(3#2'!%03$'(!'-('(!/%#3&#($#(0!'"$'(!'-(0(importância de cada requisito para o negócio.

>#-( +#-."#( 0( 0/&#"056'( $#( *-0( !0"0!&#"M+&%!0(2#"0/( $0( 0")*%&#&*"0( $#-03$0( 0/&#"05J#+( #-( A<"%0+(funcionalidades. Se aquela característica estiver de-+0!'./0$0( #( %+'/0$0F( -*%&0+( A#G#+( 0( -*$0350( .'$#(0/&#"0"(0.#30+(*-0(.0"&#(#+.#!M4!0F(0.#+0"($#/0(+#"(executada a cada funcionalidade. Imagine que no #,#-./'($'+("#/0&T"%'+(0(4/0($#(."'!#++0-#3&'(+#L0(0(princípio implementada com acesso ao banco de da-$'+F(-0+('+(_03$%32(h'3#+(-'+&"0-()*#(#++0(+'/*56'(não atende o processamento mínimo de relatórios. ;-0("#E0&'"056'(0")*%&#&*"0/(3#++#(!0+'(+#"%0(*&%/%G0"([RO(#(*-(+#"A%$'"($#(-#3+02#3+(.0"0(%-./#-#3&0"(0(4/0(#($%+&"%1*%"('(."'!#++0-#3&'($'+("#/0&T"%'+?(O#('(0!#++'(0(4/0(#+&%A#"(%+'/0$'($'(!T$%2'(E*3!%'30/F(%++'(poderá ser feito sem precisar mexer em vários locais $0(0./%!056'?((

Juntando as práticas +(."<&%!0+(0."#+#3&0$0+(3#+&#(0"&%2'(.'$#-(+#"(

*&%/%G0$0+( $#( E'"-0( %3$#.#3$#3&#( *-0( $0+( '*&"0+?(Podem também existir outras práticas que comple-mentem ou possam substituir as práticas apresen-

Figura 3. Relacionamentos entre as práticas apresentadas.

ARQUITETURA CARTOON

ARQUITETURA DE TESTES

USE STORY EXPERIMENTAL

REQUISITOS NÃO-FUNCIONAIS

INCREMENTAIS

LANDING ZONES

REAFATORAÇÕES ARQUITETURAIS

para criar referência de como a arquitetura será testada

.0"0(A0/%$0"($#!%+J#+(#($#43%"(0")*%&#&*"0(!'3!"#&0

.0"0(A#"%4!0"(&#+&01%/%$0$#(da arquitetura

.0"0(%3+#"%"()*#+&J#+(não-funcionais

incrementalmente

para ajustar atributos

para monitorar atributos não-funcionais

para ajustar limites da Landing Zone

.0"0($#43%"(*-0(arquitetura abstrata

Page 14: capa · 15 \ Um dos principais focos do desenvolvimento ágil é a criação de um código de qualidade. Práticas comuns como TDD e refatoração pos-

27 \

&0$0+?( ]01#( 0( !0$0( #)*%.#( $#!%$%"( '( )*#( *&%/%G0"( '*(não! Porém, as práticas apresentadas neste artigo 0."#+#3&0-(!#"&0(+%3#"2%0()*03$'(*&%/%G0$0+( L*3&0+F(de forma que cada uma deve ser empregada em uma E0+#($%E#"#3&#(#(.0"0(*-(."'.T+%&'($%E#"#3&#?(9#++0(forma, elas se complementam criando um método de lidar com arquitetura dentro de um projeto ágil de software.

(42*"0(\(0."#+#3&0(*-(-0.0()*#(-'+&"0(!'-'(0+( ."<&%!0+( +#( "#/0!%'30-?( ( ")*%&#&*"0( ]0"&''3( B('( ."%-#%"'( .0++'F( 30( )*0/( +#( !"%0( *-(#+1'5'( $0( 0"-quitetura focando nos principais requisitos não-fun-!%'30%+( #( $#( *-0( E'"-0()*#( E0!%/%&#( 0( !'-*3%!056'(!'-(0( #)*%.#( #( !'-('+( !/%#3&#+?(9#.'%+( $#++0( E0+#F(#3&"0(0($#43%56'($0(0")*%&#&*"0(-0%+(!'3!"#&0(!'-(0(%-./#-#3&056'($#(*-0(;+#"(O&'"S(@,.#"%-#3&0/F(#-(.0"0/#/'(!'-(0( ")*%&#&*"0($#(Z#+&#+?( (!"%056'($'+(+#"A%5'+( $0( 0")*%&#&*"0( A0%( #3&6'( '!'""#3$'($#( E'"--0( %3!"#-#3&0/( !'-( '+( e#)*%+%&'+( >6'DX*3!%'30%+(83!"#-#3&0%+?(9*"03&#('(."'L#&'(B(E#%&'(*-(0!'-.0-nhamento dos atributos mais importantes do siste-ma através das Landing Zones. Quando um limite da Landing Zone é ultrapassado, isso motiva uma Refa-&'"056'( ")*%&#&*"0/(.0"0(0(!'""#56'?( &"0AB+($0+("#-E0&'"05J#+(.'$#D+#( &#"(*-0(3'56'(-0%+( "#0/%+&0($'+(requisitos do sistema e as Landing Zones também podem ser ajustadas.

650*!8,$%9:,*&/0%!*Este artigo apresentou seis práticas para lidar

!'-(0($#43%56'F(."'L#&'(#(#A'/*56'($0(0")*%&#&*"0($#(*-(+'E&i0"#(#-(*-(0-1%#3&#(<2%/?( .#+0"($0+(."<-&%!0+(.'$#"#-(+#"(*&%/%G0$0+($#(E'"-0(%3$#.#3$#3&#F(foi também apresentado como elas possuem papéis !'-./#-#3&0"#+($#+$#(0($#43%56'(0&B(0(#A'/*56'($#(uma arquitetura. Em cada prática, foram apresenta-dos quadros com algumas dicas a respeito de como elas podem ser implementadas ou com casos reais que podem servir como referência.

b(%-.'"&03&#("#++0/&0"()*#F(0++%-(!'-'('(^7(#('(Scrum, essas práticas servem como um ponto de par-tida e que, depois de implementadas, a equipe deve evoluir de acordo com as necessidades e seu modo de trabalho. Lembre-se que “se você tem um processo ágil hoje igual ao de um ano atrás, então você não $#A#(+#"(-0%+(&6'(<2%/IF(#3&6'(36'(+#(."#3$0(0(3'-#+(e práticas, assumindo a responsabilidade do seu pro-cesso de desenvolvimento.

> Paul Clements, Felix Bachmann, Len Bass, David Garlan,

James Ivers, Paulo Merson, Reed Little, Robert Nord, Judith

Stafford. Documenting Software Architectures: Views and

Beyond, Segunda Edição.

> The Responsible Designer — “Don’t you want to take

responsibility for your designs?” — Rebecca Wirfs-Brock —

http://wirfs-brock.com/blog/

> Agilcast — “O podcast da AgilCoop!” — Episódio 12

— Arquitetura Ágil (parte 1) — http://ccsl.ime.usp.br/

!"#$%%&'(#)*'+!"#$ *,-./+012",),20 3.4+!"#3.4/3.4

& 0,)3.4-56&78)889&"*:;"%8-78<8+012",),20 8=!"#8>& 0,)8

.?8<8@,,&A''$$*#5"6)52*&5B0' !"#$%%&'(#)*'+!"#$ *,-7/

+012",),20 3.4+!"#/& 0,).56&78

> Gerard Meszaros. xUnit Test Patterns: Refactoring Test

Code

> Framework MakeATest – https://github.com/

6 0$2*C%0" D%'6 E) ,)*,/$%0)

> Kerievsky, Joshua. Refactoring to Patterns.

> Muller, Gerrit. From Legacy to State-of-the-art;

Architectural Refactoring.

> Stal, Michael. Software Architecture Refactoring. http://

FFF5*"!*5;)';%FD#% ;'%%&G4H'I, #3.4J"7/K5&;L

> Michael Stal on Architecture Refactoring — http://

www.infoq.com/interviews/michael-stal-on-architecture-

refactoring

/referências

M 8);"NO%8-PQ8%8 0,"!%8RS)C)TO%8U8+D%, NV)*8<8W6 8

X%6B"D NO%89T&#%*"Y Z8 &0)*)D, 8*",2 NV)*8)6812)8 8

0)C)TO%8)8 D%, NV)*8&%;)68*)082,"#"[ ; *8& 0 8$0" 08

*%#2NV)*86 "*8"D,)#"!)D,)*5

A edição 32, o artigo “Proxys Estáticos e Dinâmicos”

mostrou as técnicas que podem ser utilizadas para

adicionar funcionalidades nas classes através de proxys.

+8*)12\D$" 8;)8 0,"!%*8D *8);"NV)*8.7Q8.K8)8.]Q8$@ 6 ;%*8

respectivamente “Testes Unitários para Camadas de

Negócios no Mundo Real”, “Testes de Unidade para

Camadas de Persistência no Mundo Real” e “Testes de

Unidade para Camadas de Apresentação no Mundo

Real” apresentam técnicas para criar testes de unidade

para diversas camadas de uma aplicação. Eles podem ser

utilizados como referência para a criação da arquitetura

de testes.

M *8);"NV)*8K]8)8KHQ8%*8 0,"!%*8R^0%!0 6 NO%8_0")D, ; 8

a Aspectos para Leigos” e “Explorando Funcionalidades

de Static Crosscutting do AspectJ” apresentaram o uso

de aspectos que podem ser utilizados para uma evolução

transparente da arquitetura.

para saber mais/