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

Post on 24-Mar-2020

5 views 0 download

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

/ 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

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+%&(%'/=./("#&(

/ 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.

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.

/ 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

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!

/ 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); } } }

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-

/ 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

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?

/ 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'(

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); } } }

/ 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

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/