Comentários livros: Agile Sofware Development

Agile, Scrum, TDD 1 Comment »

Nos últimos três meses tive a oportunidade de ler dois ótimos livros relacionados a desenvolvimento ágil. Com abordagem envolvente ambos os livros conseguiram manter minha concentração nas madrugas mesmo após dias estressantes no trabalho. Acredito após a leitura dos dois livros acabei aperfeiçoando minhas técnicas de desenvolvimento, tanto a nível de design de solftware quanto minha postura diante processos.

O livro Agile Software Development, Principles, Patterns, and Practices escrito pelo Robert Martin aborda alguns conceitos de XP e foca bastante em mostrar as vantagens de usar abordagens TDD com intuito de criar códigos mais legíveis e reutilizáveis. Particularmente, o primeiro estudo de caso foi o melhor, mostra detalhadamente passos de refatoração como nomes de métodos mais claros, extrair classes, métodos. Martin introduz cinco princípios:

  • SRP - Single Responsabity Principle
  • OCP - Open Closed Principle
  • LSP - Liskov Substitution Principle
  • DIP - Dependence Inversion Principle
  • ISP - Interface Segregation Principle

Se você deseja escrever códigos melhores, recomendo ler estes cinco princípios. Além destes cinco princípios, o livro aborda diversos patterns conhecidos da literatura, mas em uma abordagem diferente. E sempre com um estudo de caso para aplicar os patterns abordados. Muito bem estruturado.

Esta semana finalizei a leitura do livro Agile Software Development with Scrum. Quando eu comprei este livro, pensei que ele abordava os conceitos do Scrum. Por outro lado há dicas de algumas atitudes a serem tomadas Daily Meetings, Sprint Plannings que evitam situações que conduzem ao fracasso do projeto.

Do início ao fim do livro há relatos de estudos de casos de sucesso mostrando como o Scrum mudou o rumo de diversos projetos. Este livro ajudou a consolidar minha opinião de que para implantar o Scrum ou qualquer outro método ágil em um projeto é preciso de uma disciplina forte. São muitos mitos a serem quebrados, e dependendo da organização e da maturidade do time é uma tarefa um pouco complicada.

Exemplo: não é fácil reunir-se diariamente no mesmo horário e durante 15 minutos exatos. E por ser uma situação que evidencia para todo o time a produtividade do desenvolvedor, alguns profissionais começam a criar resistência (através de atrasos as reuniões) tornando-se um grande risco durante os primeiros projetos.

É como Ken Schwaber diz em em seu último parágrafo, em outras palavras: “Scrum não é para todos apenas para pessoas dispostas a matar ‘leões’ diariamente”.

Como a vida não pára, agora vou quero aprofundar um pouco mais os meus conhecimentos em Ruby principalmente em Rails. Além de artigos, o user guide, estou começando a ler o livro do Rodrigo Urubatan, e pelas primeiras páginas que já li, o livro parece ser bem legal, assim que finalizar a leitura deixo aqui meus 5 centavos. :)

FacesContext em Seam Remoting calls

Java, Java EE, Java Server Faces, Jboss Seam No Comments »

Faz um tempinho que não escrevo nada por aqui. Além de projetos críticos que estou participando, estava muito envolvido na leitura de dois livros relacionados a Agile, que os comentarei em breve, e também estou escrevendo uma série de artigos para a revista Java Magazine, o primeiro sai na edição 72. A partir de agora devo publicar pelo menos uns 2 post mensais. ;)

O Seam Remoting oferece uma forma conveniente de acessar componentes backing beans via AJAX. Com uma simples anotação é possível chamar ações, intanciar objeto e etc. Porém este recurso é uma maneira limitada de acessar o contexto dos componentes e requer uma certa atenção de nós desenvolvedores. Pessoalmente, pude presenciar soluções fantásticas usando remoting e mas algumas implementações desastrosas. Fica a dica: use o remoting apenas quando os componentes AJAX existentes não solucionam um dado problema.

Por padrão, uma requisição AJAX via Seam Remoting não possui controle de transações e o contexto JSF não é criado. Para ambos os casos é possível habilitá-los. O controle de transações é mais simples, basta adicionar a anotação @Transactional com o tipo REQUIRED. Veja o exemplo:

@WebRemote @Transactional(TransactionPropagationType.REQUIRED)
public void updateUserProfile(Profile profile) {
entityManager.merge(profile);
}

Criar o contexto JSF exige algo um pouco mais avançado. Antes de iniciar a execução das ações, o contexto JSF deve ser criado, e para a sua criação é preciso o HttpServletRequest e o HttpServletResponse. Uma forma seria criando um filtro, mas acredito que não é uma boa solução. O Seam possui um recurso de ExecutionHandler que permite executar determinadas operações em requisições Remoting antes executar a ação. Este recurso usa o padrão Observer, onde o primeiro passo é criar o observer, ele precisa de implementar a interface ExecutionHandler:

public class RemotingFacesContextHandler extends ExecutionHandler {

private ServletContext servletContext;

protected FacesContext getFacesContext(HttpServletRequest request,
HttpServletResponse response) {

FacesContext facesContext = FacesContext.getCurrentInstance();

if (facesContext == null) {
FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
facesContext = contextFactory.getFacesContext(servletContext,request, response, lifecycle);
}

return facesContext;
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
getFacesContext(request, response);
super.handle(request, response);
}
@Override
public void setServletContext(ServletContext ctx) {
this.servletContext = ctx;
super.setServletContext(ctx);
}
}

O método handle chama o método getFacesContext que é responsável por iniciar o contexto. A inicialização do FacesContext é feita por meio do método getFacesContext da classe FacesContextFactory. Além do contexto servlet, do request e do response, é necessário informar o ciclo de vida JSF.O Ciclo de vida é criado por meio da classe LifecycleFactory.

Uma vez criado o observer, basta registrá-lo. Uma das várias alternativas é registrá-lo após a inicialização usando a anotação @Observe:

@Name("registerHandler")
public class RegisterFacesContextHandler {
private static final String REQUEST_PATH_EXECUTE = "/execute";

@Observer("org.jboss.seam.postInitialization")
public void initHandler() {
RequestHandlerFactory.getInstance().registerHandler(REQUEST_PATH_EXECUTE, new RemotingFacesContextHandler());

}

}

Após inicializado o Seam (org.jboss.seam.postInitialization) o observer é registrado. Com isto você pode chamar FacesContext.getCurrentInstance() que não receberá aquele NullPointerException indesejado. ;)

Generator do Seam 2.1 não é compativel com 2.0.x

Java, Java EE, Java Server Faces, Jboss Seam 8 Comments »

Fazendo alguns testes com o Seam acabei descobrindo uma falha de compatibilidade do Seam Generator da versão 2.1 com as versões anteriores. O problema reside nos filtros que são criados nas páginas de listagens.

Nas versões anteriores, o componente para as páginas de listagens sobrescreviam os métodos:
- getEjbql: Consulta EJB QL usada para a listagem.
- getMaxResults: Define a quantidade de registros a serem retornados pela listagem.
- getRestrictions: Retorna lista de restrições a serem adicionadas a consulta.

Porém na versão 2.1 estes métodos deixaram de ser usados na geração do código. O problema é que o método getRestrictions teve o retorno aterado. Nas versões anteriores ele retornava uma lista de Strings, já na versão 2.1 o tipo de retorno foi alterado para uma lista de ValueExpression.

Com isto um código gerado na versão na versão 2.0.3, por exemplo, gera ClassCastException ao tentar converter String em ValueExpression. Solução? Atualizar o código, veja o antes e o depois:

@Name("userList")
public class UserList extends EntityQuery {

private static final String[] RESTRICTIONS = {
"lower(user.login) like concat(lower(#{userList.user.login}),'%')",
"lower(user.name) like concat(lower(#{userList.user.name}),'%')"};

private final User user = new User();
@Override
public String getEjbql() {
return "select user from User user";
}

@Override
public Integer getMaxResults() {
return 25;
}

public User getUser() {
return user;
}

@Override
public List<string> getRestrictions() {
return Arrays.asList(RESTRICTIONS);
}

}

A versão 2.1 o código gerado é algo semelhante a:

@Name("userList")
public class UserList extends EntityQuery<user> {

private static final String EJBQL = "select user from User user";

private static final String[] RESTRICTIONS = {
"lower(user.login) like concat(lower(#{userList.user.login}),'%')",
"lower(user.name) like concat(lower(#{userList.user.name}),'%')"};

private final User user = new User();

public UserList() {
setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
setMaxResults(25);
setEjbql(EJBQL);
}

public User getUser() {
return user;
}
}

Até que seja corrigido o problema fica a dica.

URL Amigáveis com Seam 2.1

Java, Java EE, Java Server Faces, Jboss Seam No Comments »

Desenvolver aplicações com URL amigáveis em projetos JSF não é uma tarefa fácil. Porém ao utilizar o Seam, esta tarefa é muito facilitada. A versão 2.1 traz a integração nativa com o URLRewrite, simplicando ainda mais o desenvolvimento.

Meu objetivo neste post é mostrar as diferenças para implementação da mesma funcionalidade na versão 2.0 e a versão 2.1. Até a versão 2.1 era necessario (sem acento mesmo, dentro da reforma ortográfica) a criação de um Adapter. Vejamos como era feito, há até uma vídeo aula publicada sobre o assunto, primeiro vamos ao Adapter, necessário para fazer com que o URLRewriter resolva as URLs:

@Startup
@Scope(ScopeType.APPLICATION)
@Name("seamUrlRewriterFilter")
@BypassInterceptors
@Filter(within="org.jboss.seam.web.ajax4jsfFilter")
@Install(classDependencies="org.tuckey.web.filters.urlrewrite.UrlRewriteFilter",
precedence=Install.APPLICATION)
public class SeamUrlRewriterFilter extends AbstractFilter {

private UrlRewriteFilter urlRewriteFilter;
private Map initParameters;

public void init(FilterConfig filterConfig) throws ServletException {
urlRewriteFilter = new UrlRewriteFilter();
urlRewriteFilter.init(new FilterConfigWrapper(filterConfig, getInitParameters()));
}

public Map getInitParameters() {
return initParameters;
}

public void setInitParameters(Map initParameters) {
this.initParameters = initParameters;
}

public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
urlRewriteFilter.doFilter(arg0, arg1, arg2);
}

private class FilterConfigWrapper implements FilterConfig {

private FilterConfig delegate;
private Map parameters;

public FilterConfigWrapper(FilterConfig config, Map parameters) {
this.delegate = config;
this.parameters = parameters;
}

public String getFilterName() {
return delegate.getFilterName();
}

public String getInitParameter(String arg0) {
if (parameters.containsKey(arg0)) {
return (String) parameters.get(arg0);
} else {
return (String) delegate.getInitParameter(arg0);
}
}

public Enumeration getInitParameterNames() {
Enumeration[] enumerations = {delegate.getInitParameterNames(),
Collections.enumeration(parameters.entrySet())};
return new EnumerationEnumeration(enumerations);
}

public ServletContext getServletContext() {
return delegate.getServletContext();
}
}
}

Você pode estar pensando: porque não declarar o filtro diretamente no web.xml? Precisamos garantir que ele seja executado após filtro do RichFaces, através da anotação @Filter(within=”org.jboss.seam.web.ajax4jsfFilter”). Também é importante que este filtro esteja dentro do contexto seam. Para que este Adapter funcione adequadamente,  devemos registrá-lo no arquivo component.xml para que as URL’s sejam interpretadas.

<component name="seamUrlRewriterFilter" class="jm.seamtest.core.SeamUrlRewriterFilter" precedence="30">
<property name="initParameters">
<key>logLevel</key>
<value>DEBUG</value>
<key>statusEnabled</key>
<value>false</value>
</property>
</component>

Já na versão 2.1, todas estas configurações não são mais necessarias. Basta adicionar esta tag no arquivo de configurações do seam, components.xml:

<web :rewrite-filter view-mapping="*.seam" />

Vamos imaginar como exemplo de URL amigável, a url usada neste blog para visualização de posts: /ano/mes/dia/titulo-uuid. Vamos analisar como era as configurações nas versões anteriores, a configuração do padrão de url era realizado diretamente no arquivo de configurações nativo do URLRewrite:

<rule enabled="true">
<from casesensitive="true">^/([0-9]{4})/([0-9]{2})/([0-9]{2})/([A-Z0-9]+[A-Za-z0-9]*)?$</from>
<to>/post/showpost.seam?ano=$1&mes=$2&dia=$3&tituloUUID=$4</to>
</rule>

O URLRewrite, exige do desenvolvedor conhecimentos de expressões regulares. Além do mapeamento da URL, é necessário vincular os parâmetros passados pela URL, uma das formas é usando Page Actions:


<page view-id="/post/showpost.xhtml">
<param name="ano" value="#{viewPostBean.ano}" />
<param name="mes" value="#{viewPostBean.mes}" />
<param name="dia" value="#{viewPostBean.dia}" />
<param name="tituloUUID" value="#{viewPostBean.tituloUuid}" />
<action execute="#{viewPostBean.show}" />
</page>

Na versão 2.1, não é mais necessária a configuração nativa, tudo que precisamos é de uma simples tag para mapear a url dentro da Page Action.


<page view-id="/post/showpost.xhtml">
<rewrite pattern="/{ano}/{mes}/{dia}/{tituloUUID}"/>
<param name="ano" value="#{viewPostBean.ano}" />
<param name="mes" value="#{viewPostBean.mes}" />
<param name="dia" value="#{viewPostBean.dia}" />
<param name="tituloUUID" value="#{viewPostBean.tituloUuid}" />
<action execute="#{viewPostBean.show}" />
</page>

O padrao de URL “/{ano}/{mes}/{dia}/{tituloUUID}” pode é traduzido em  /post/showpost.xhtml?ano=2009&mes=03&dia=16&tituloUUID=url-amigavel. Neste caso todas as variáveis entre chaves são transformadas em parâmetros HTTP. Simples não?

WP Theme & Icons by N.Design Studio
Assine Assine os comentarios