Como você organiza seu código?

Muitas práticas de programação tem como objetivo principal facilitar a leitura do programa, uma delas é a organização de código. Toda linguagem tem alguma forma de empacotar e dividir a lógica de negócio, mas que ao final não fazem tanta diferença assim na execução do programa.

Apesar de parecer ser uma atividade simples, organizar o código é algo que eu nunca havia pensado com muitos detalhes antes, até que um amigo me apontou para um artigo que apresenta quatro estratégias para organizar seu código.

Na grande maioria dos códigos em que trabalhei, a divisão mais comum é a por tipo, que organiza os pacotes baseado na função que cada classe desempenha. Aplicações Rails por exemplo são automaticamente geradas seguindo esse paradigma.

Captura de Tela 2016-05-21 às 6.56.39 AM

Todos os modelos ficam em uma pasta dedicada, todos os arquivos de configuração ficam em outra. No entanto o que isso te diz sobre o domínio da sua aplicação? Será que a organização das pastas deveria te dizer algo sobre o domínio? Recomendo assistir a apresentação Architecture the Lost Years, de Bob Martin, para ver mais detalhes sobre esse ponto.

Não é que essa organização esteja errada, o programa continuará funcionando normalmente e desenvolvedores conseguem entender a arquitetura e navegar pelo o código. O problema é pensar que essa é a única maneira de organização!

Na maioria dos projetos com frameworks Java que já vi é comum encontrar divisão por pacotes que não agrega nenhuma informação lógica – mesmo não sendo frameworks com convenções tão forte como Rails.

Por exemplo, todas as classes ficam dentro do pacote br.com.empresa.nomeDoProjeto, o único conteúdo do pacote br é o pacote com, que também tem como único conteúdo o pacote empresa… até que, depois de vários pacotes “vazios” chegamos ao código real.

O problema da má organização de pacotes é que isso pode forçar a complicar mais os nomes das classes. Tanto que existe um jogo Java: Real or Not? onde precisamos escolher qual classe é real do framework Spring entre outras duas que são inventadas.

Mesmo em projetos que usam frameworks com forte convenção, como Rails, é possível adaptar o código para que ele seja organizado de uma maneira diferente, como mostrado no post Baking a Cake with Rails.

Se você prefere organizar pacotes por componentes, por camadas ou qualquer outra forma, é possível! O objetivo é tornar a arquitetura e design mais explícitos, não seguir cegamente um framework, como descrito no post Screaming Architecture.

Como falei no começo, organização de código é algo que só comecei a me preocupar de verdade recentemente, mas já pude ver que, ao utilizar uma abordagem de divisão por componente o código fica bem mais conciso e fácil de navegar.

E você, já tinha parado pra pensar em como organiza seu código antes? Qual sua maneira preferida?

Porque nomear um atributo como “type” não é uma boa ideia em Rails.

Ou: como utilizar o padrão Herança de Tabela Única (Single Table Inheritance) em Rails.

Se alguma vez você já tentou criar um atributo chamado “type” no seu modelo Active Record, provavelmente você teve algum problema, ou já sabia exatamente o que estava fazendo. Se você se encaixa no primeiro grupo, então esse post talvez possa lhe ajudar um pouco.

Um pequeno exemplo

Vamos criar um scaffold usando Rails da seguinte maneira:

rails generate scaffold Dealer name type company

Criamos o Dealer (Negociante) que no nosso dominio tem os atributos nome (nome da pessoa) e empresa (empregador). Adicionamos também um campo type, esse campo deve ter os valores “Seller” caso seja um vendedor ou “Buyer” caso seja um comprador.

Agora vamos no rails console para criar um novo Dealer da seguinte maneira:

Dealer.create name: "Zeca", company: "Uburu Inc", type: "Seller"

A seguinte exceção será lançada: ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: Seller is not a subclass of Dealer.

O começo da mensagem diz que o tipo da herança de tabela única é invalido pois a classe Seller não é uma subclasse de Dealer. Vamos ver um pouco mais sobre o padrão Single Table Inheritance (STI) [1]

Single Table Inheritance

O padrão STI está catalogado como parte dos Padrões de Arquitetura de Aplicações Empresariais (Patterns of Enterprise Application Architecture). O cenário de aplicação do padrão é quando você precisa representar uma herança em uma base de dados relacional.

A ideia para resolver o problema é bem simples, vamos adicionar um campo que vai dizer qual subclasse deve ser instanciada com aqueles dados. Voltando ao exemplo do post, podemos então ter uma superclasse chamada Dealer e duas subclasses Seller/Buyer que vão ter os mesmos atributos, mas lógicas diferentes.

O Rails já vem pronto para utilizarmos o STI. Basta utilizar que chamemos o campo que diferencia a classe de ‘type’. Por isso, no exemplo anterior, aquele exceção foi lançada. Criamos o modelo Dealer, mas ainda não temos o modelo Seller ou Buyer.

Para resolver o problema vamos criar o Seller e Buyer e fazer com que elas herdem de Dealer. Note que as classes Seller e Buyer não precisam herdar da classe ActiveRecord pois elas vão herdar de Dealer. O código seria algo do tipo:

class Seller < Dealer
end

Agora, se tentarmos criar o mesmo objeto de antes, veremos a seguinte saida:

Dealer.create name: "Zeca", company: "Uburu Inc", type: "Seller"
=> #<Seller id: 1, name: "Zeca", type: "Seller", company: "Uburu Inc", created_at: "2013-11-14 00:51:55", updated_at: "2013-11-14 00:51:55">

Ou seja, mesmo criando um Dealer, o Rails sabe que se trata de um Seller, graças ao STI. Se tentarmos criar um Seller também conseguimos o mesmo resultado:

Seller.create name: "Zeca", company: "Uburu Inc"
=> #<Seller id: 2, name: "Zeca", type: "Seller", company: "Uburu Inc", created_at: "2013-11-14 00:57:36", updated_at: "2013-11-14 00:57:36">

Veja também que o Rails já colocou o valor do atributo ‘type’ para “Seller” automaticamente. Assim você não precisa se preocupar em sempre criar um “Dealer” com o ‘type’ sendo “Seller” ou “Buyer”, basta utilizar a classes que você realmente precisa.

Se o nosso objetivo fosse só ter um campo chamado ‘type’ mas sem nenhuma herança podemos simplesmente renomear o campo para ‘alguma_coisa_type’ ou, se isso não for possível, podemos adicionar a seguinte linha na implementação da classe:

class Seller < ActiveRecord::Base
  self.inheritance_column = nil
end

Assim, o Rails não vai mais se importar com o ‘type’ para herança. Ou caso você precise configurar o atributo que define a herança como outro nome, também é possível passar o nome desejado para que o Rails trate o modelo como uma implementação do STI.

Referências

1. Martin Fowler, Single Table Inheritance. http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html

Cuidado ao cortar sua arquitetura

Quando estamos modelando o nosso sistema, é bem comum pensarmos em camadas. Talvez um dos modelos de maior sucesso no mundo do desenvolvimento (web ou não) é o MVC. A separação em camadas é bem interessante e facilita bastante a separação de responsabilidades e definição de limites.

No entanto, por mais lógico que pareça separar o desenvolvimento por camadas, dificilmente ajuda. Imagine a seguinte situação: uma nova funcionalidade precisa ser desenvolvida, pra simplificar pense num CRUD qualquer. Como você dividiria essa tarefa entre as pessoas da sua equipe?

Cortes horizontais

Dividir a tarefa em camadas, onde um par vai trabalhar no modelo (provavelmente mudando o banco de dados) e outro par fazendo a parte de views (fazendo algo na interface), pode parecer a decisão correta, afinal você pode colocar o especialista em banco de dados pra fazer a parte de modelos e outra pessoa que detona em CSS pra construir uma boa interface.

O problema dessa divisão é que ela exige uma sincronia muito grande entre a equipe. E (aqui vem um dos piores males do desenvolvimento de software) abre um espaço gigantesco para suposições.

O par que está desenvolvendo o back-end precisa construir tudo o que o par que vai trabalhar na interface vai precisar. E se a comunicação não acontecer, muita coisa pode ser feita a mais ou a menos. Esse é o maior perigo quando são feitos cortes horizontais na arquitetura.

Cortes Verticais

Agora imagine que, ao implementar a mesma funcionalidade de CRUD, vamos dividir as tarefas em ações. Então um par faz a parte de criação, por exemplo, e outro faz a visualização.

Obviamente a comunicação precisa acontecer para garantir que tudo seja feito de maneira homogênea, os nomes das tabelas são os mesmos, as views seguem os mesmos estilos, etc. Mas a comunicação sempre precisa acontecer, esse é o real segredo de projetos bem sucedidos!

No entanto, o par que desenvolve a visualização das entidades sabe exatamente o que vai ser necessário nos modelos para que as views funcionem. Assim, minimizamos o espaço para suposições, pois cada par pode implementar exatamente o necessário, nem mais nem menos.

O que é Arquitetura Ágil?

De uma maneira simples e rápida: é a aplicação do pensamento enxuto nas práticas arquiteturais.

O pensamento enxuto é a busca pela maximização do valor através da contínua eliminação de desperdícios. O desenvolvimento ágil é fortemente baseado no pensamento enxuto. Apesar de que as metodologias definem várias práticas, valores, princípios, etc, etc, etc… No fim, tudo o que elas buscam é: maximizar o valor eliminando desperdícios.

Por isso você dificilmente conseguirá achar um time ágil que escreve um Documento de Visão [2], dada a sua grandiosíssima utilidade para o projeto. No entanto, se a equipe trabalha, por exemplo, para órgão públicos, os documentos são extremamente necessário, então, neste caso, os documentos trazem sim valor ao projeto, não devendo ser eliminados.

A Arquitetura Ágil então busca aplicar este pensamento, de cortar desperdícios, e agregar mais valor ao cliente. As definições mais clássicas de arquitetura definem como “a estrutura organizacional dos seus componentes e o relacionamento entre estes” [3]. Com base nisso surgiram várias práticas arquiteturais para realizar esta análise, como modelos, diagramas, entre outros. Mas a verdade é que “a estrutura organizacional dos seus componentes e o relacionamento entre estes”, por si só, não traz nada para o cliente, ou projeto.

Entra então a Arquitetura Ágil. Nos trabalhos mais atuais, quando se fala de Arquitetura, é muito comum falar sobre atributos de qualidade [4], ou seja, agora a Arquitetura não é só uma visão da implementação, ela também traz valor ao projeto, ao buscar alcançar determinados atributos de qualidade, e isso sim traz um real valor.

Um bom exemplo de atributo de qualidade é o tempo de resposta para criação de um relatório. Como poderíamos destacar que o tempo de resposta para gerar um certo conjunto de relatórios, em determinada situação, seja igual a 10 segundos, por exemplo? A equipe não consegue descrever uma estória sobre isso, pois essa é uma preocupação constante no projeto e não algo que vai ser testado e implementado para ser feito o deploy.

A Arquitetura Ágil vai então propor atividades que tragam a atenção do time para esta tarefa. Para este exemplo, poderia ser utilizado a prática de Landing Zones [5], onde seria definido valores mínimo, ideal e máximo para o tempo de criação do relatório. Assim a equipe poderia escrever um teste que, ao quebrar estes limites alertaria um problema.

Existem ainda vários outros pontos de discussão, como onde encaixar a arquitetura, se é preciso realmente uma preocupação com a arquitetura, quem é o arquiteto, ou “Quem  precisa de um arquiteto?” [6]

Se você quer saber mais sobre Arquitetura, compareça a JavaCE Comunity Conference (http://conference.javace.org/) e vote no meu LT (http://call4paperz.com/events/javace-conference-lightning-talk/proposals/388) para ser um dos palestrantes no evento.

[1] Lean Thinking. http://www.lean.org.br/o_que_e.aspx

[2] Documento de visão. http://pt.wikipedia.org/wiki/Documento_de_visão

[3] VAROTO, A. C. Visões em arquitetura de software. Dissertação de Mestrado, Universidade de São Paulo, São Paulo, SP, 2002.

[4] SHARIFLOO, A. A.; et al. Embedding Architectural Practices into Extreme Programming . 19th Australian Conference on Software Engineering , 2008.

[5] GUERRA, E. Práticas para lidar com Arquitetura em ambientes ágeis. MundoJ, Nov/Dez, 2011

[6] FOWLER, M. Who Needs an Architect? IEEE Software, Jul/Ago, 2003