Pesquisar

quarta-feira, 9 de janeiro de 2008

Ruby: usando classe aberta (open classe)

Extender (não no sentido "carregado" da herança) uma classe já existente.... Interessante recurso, lembro de algo similar no mundo .net os extension methods.

#uma classe já existente.
class Integer

#adicionando métodos a mesma.
def am(*args)
self == 12 ? 0 : self
end

def pm(*args)
self == 12 ? 12 : self +12
end
end


#veja que interessante o uso.
i = 4.pm
puts "4Pm = " << i.to_s #deve aparecer 4Pm = 16
i = 4.am
puts "4Am = " << i.to_s #deve aparecer 4Am = 4

#outro exemplo...
class String
def em_maisculo
self.upcase
end
end

puts "galaxy".em_maisculo



Esse recurso pode facilitar a escrita de interfaces fluente... imagine.
compromisso.adicionar("ler algo sobre ddd").comecando_as(2.Pm).ate_as(4.Pm).hoje()


* Exemplos inspirados numa apresentação de um trabalhador da throughworks.

"Interface fluente" no JavaScript

Isso mesmo "já embutida":
Ao invés de fazer isso.

elemento = document.getElementById("attachments-box");
elemento.removeAttribute("width");

elemento1 = document.getElementById("format_auto");
elemento1.setAttribute("checked", "true");

Você pode fazer diretamente:
document.getElementById("attachments-box").removeAttribute("width");
document.getElementById("format_auto").setAttribute("checked", "true");

E só pra não perder o costume mais um link de um belo exemplo de uma interface fluente: http://gc.blog.br/2007/09/25/refatorando-para-fluent-interface/

sexta-feira, 4 de janeiro de 2008

Expressividade na linguagem

Atualmente existem muitas linguagens de programação no mercado, algumas que fazem parte do "legado" {cobol,natura...} e outras estão em "voga" {java,ruby,c#...}. Fala-se muito em expressividade na escrita de código. A linguagem pode ajudar e muito a criação de código mais expressivo. Como exemplo inicial, duas linguagens, Java já conhecida e admirada e Ruby nova e promissora.
Para se obter o ultimo elemento de uma lista...

Em Java.
aList.get(aList.size -1)
Em Ruby.
anArray.last

É notório que o código parece ser melhor expresso com Ruby.
Agora considere os códigos abaixo:

//C# 2.0
date d = Helper.At(Helper.FromToday(Helper.Days(2)), Helper.Pm(4));
//C# 3.0
date d = 2.Days().FromToday().At(4.Pm);
Veja o quanto a versão 3.0 do sharp é mais fácil de ser "lida".

Outro exemplo:

Em Java:
public List pessoasFisicas(List pessoas) {
List resultado = new ArrayList();
for (Pessoa pessoa : pessoas)
if (pessoa.isFisica()) result.Add(pessoa);
return result;
}

Em Ruby:
def pessoasFisicas(pessoas)
return pessoas.select {|e| e.isFisica}
end

Sem comentário para essa última demonstração.
"Ser expressivo" pode facilitar futuras manutenções, extensões e integrações no código.

Os exemplos foram roubados discaradamente de
* HumaneInterface - Martin Fowler
* Artigo no InfoQ

ps: os códigos podem estar errados.

quinta-feira, 3 de janeiro de 2008

Ótimo post sobre Interface Fluente.

No site abaixo verá um exemplo bastante interessante, principalmente para quem trata requisições (no modelo "JSP/Servelt") em páginas.
http://fragmental.tw/2007/10/18/notes-on-language-adaption/
Enjoy it.

sexta-feira, 30 de novembro de 2007

Fluent Interface ...

Primeiro a definição depois os exemplos.

*DSL ==> *é uma linguagem (mini liguagem) projetada para um tipo especifico de tarefa, isto é justamente o contrário de linguagens para proposito geral como Java, C ou C#.
*Fluent Interface (Interface Fluente)* ==> objeto que é capaz de deixar as suas responsabilidades mais expressivas a linguagem. (:S confuso, mas o exemplo ajudará)

Para se aprender algo nada melhor do que exemplos./ (aprender com exemplos não dá sono de acordo com Fowler, eu acho que ele está certo)/
Irei apresentar aqui dois exemplos: um simples e outro mais interessante.

*Exemplo Simples*

Supondo que tenho um objeto que representa o conceito Carro.

public class Carro{
private String nome;
private String marca;
private int portas;
public Carro(){
}
// métodos de acesso as propriedades encapsulados...
}

Quando fossemos "usar" esse objeto fariamos...

//***
Carro fusca = new Carro();
fusca.setNome("fusca");
fusca.setMarca("VW");
fusca.setPortas(2);
//***

Tentando aplicar o conceito de Interface Fluente, definiriamos uma Interface

public interface ICarro{
ICarro setNome(String nome);
ICarro setMarca(String nome);
ICarro setPortas(int nome);
}


//classe que implementa essa interface.
public class Carro implements /ICarro/{
private String nome;
private String marca;
private int portas;
public Carro(){
}

public ICarro setNome(String nome){
this.nome = nome;
return this;
}
public ICarro setMarca(String nome){
this.nome = nome;
return this;
}
public ICarro setPortas(int numero){
this.portas = numero;
return this;
}

}

*Agora nosso mesmo exemplo.( O simples ainda )*

//** ANTIGO
Carro fusca = new Carro();
fusca.setNome("fusca");
fusca.setMarca("VW");
fusca.setPortas(2);
//**

//** COM O CONCEITO DE INTERFACE FLUENTE
Carro fusca = new Carro();
fusca.setNome("fusca")
.setMarca("VW")
.setPortas(2);
//Note como cada método de set retorna o objeto aplicando outro método,
dando mais expressividade
//a linguagem.
//**

Isso parece meio bobo, mas para um *exemplo inicial* é até "bonzinho".


*Exemplo Interessante

*Outro possível exemplo, um criador de sql. Em tempos que o padrã JPA está se consolidando, se trata de exemplo não muito usual (sem bem que se pode usar-lo para criar as JPQL)... mas ao exemplo.
Se quiser "conversar" com o SGBD expresse em SQL. Uma consulta SQL é
similar ao exemplo abaixo:*

SELECT* campo1,campo2, campo4 (ou * para todos)
*FROM* tabela1
*[INNER | OUTER ...] JOIN* tabela2 *ON*
*WHERE* condicao1
*AND *condicao2
*OR* condicao2
*ORDER BY* campo1, campo2 ....

O exemplo acima não mostra todas as potencialidades da linguagem SQL mas serve para o propósito do exemplo.

1º A criação da Interface

public interface IConsultaSql{
IConsultaSql select(String campos);
IConsultaSql from(String tabela);
IConsultaSql innerJoin(String tablea);
IConsultaSql outterJoin(String tablea);
IConsultaSql on(String condicao);
IConsultaSql where(String condicao);
IConsultaSql and(String condicao);
IConsultaSql or(String condicao);
IConsultaSql orderBy(String campos);
}

Logo após a criação da classe que implementa a interface.

public class ConsultaSql implements /IConsultaSql/{
private StringBuilder construtor = new StringBuilder();
//note que o próprio StringBuilder aplica conceitos de interface fluente.
public ConsultaSql(){
}

public IConsultaSql select(String campos){
construtor.append("SELECT ")
.append(campos);
return this;
}

public IConsultaSql from(String tabela){
construtor.append(" FROM ")
.append(tabela);
return this;
}

public IConsultaSql innerJoin(String tabela){
construtor.append(" INNER JOIN ")
.append(tabela);
return this;
}
public IConsultaSql outterJoin(String tabela){
construtor.append(" OUTTER JOIN ")
.append(tabela);
return this;
}
public IConsultaSql on(String condicao){
construtor.append(" ON ")
.append(condicao);
return this;
}
public IConsultaSql where(String condicao){
construtor.append(" WHERE ")
.append(condicao);
return this;
}
public IConsultaSql and(String condicao){
construtor.append(" AND ")
.append(condicao);
return this;
}

public IConsultaSql or(String condicao){
construtor.append(" AND ")
.append(condicao);
return this;
}
public IConsultaSql orderBy(String campos){
construtor.append(" ORDER BY ")
.append(condicao);
return this;
}

public String getSql(){
String retorno = construtor.toString();
return retorno;
}
}

*Veja o uso.*

ConsultaSql con = new ConsultaSql();
con.select("nome,telefone")
.from("pessoa_fissica pf").innerJoin("contatos ct").on("pf.id=ct.pf_id")
.where("pf.nome like %?%")
.and("pf.idade>18").orderBy("nome,idade");

*Bem mais expressivo... mais flexível*

Senão engano o Hibernate está implementando [ou tem implementado] algo assim para criar os
objetos Criteria.

public String getSql() throws SqlIncorretoException{
String retorno = construtor.toString();
Sql.valida(retorno);
return retorno;
}


Uma nova característica do java 5, o varargs também pode ajudar a aplicar "esses novos conceitos" de interface fluente.

*TRADICIONALMENTE*
Produto bola;
Produto cafe;
Produto monitor;
Compra compra = new Compra(cliente);
compra.adicionarItem(bola);
compra.adicionarItem(cafe);
compra.adicionarItem(monitor);

*COM USO DE VARARGS
*
Produto bola;
Produto cafe;
Produto monitor;
Compra compra = new Compra(cliente);
compra.adicionarItem(bola,cafe,monitor);

Enfim são todos conceitos muito abstratos e ainda em discussão, logo "nada" é certo sobre esse tema. No mínimo o assunto é interessante e intrigante para os desenvolvedores e clientes (quem realmente interessa). Se acostume com esse novo paradigma /expressividade no desenvolvimento. (tudo mais perto da linguagem de
domínio do sistema)

/ps: perdoem os erros de português.
/Links interessantes sobre os assuntos/.

* _http://www.fragmental.tw_ (Blog sobre pesquisa em DSL)
* _http://martinfowler.com/bliki
/FluentInterface.html_ (Fowler
"ditando" sobre o que é uma Interface Fluente)
* _http://www.infoq.com/presentations/domain-specific-languages_
(Vídeo com uma introdução sobre DSL)

Da arte de integrar sistemas algo é certo... (um pouquinho de S.O.A.)

Integrar sistemas --> Pode ser entendido como a "arte" de interligar diversos sistemas que precisam de SERVIÇOS (não somente dados, além disso é necessário inteligência) dos demais. Essa interligação pode ser feita de diversas formas [implementadas] por exemplo:
Usando WebServices.
Usando RCP. (RMI, COM+ ...)
Usando Tabelas Corporativas.
Usando outros sistemas como "ponte". (sistemas para integração de aplicações)
...

Premissas
É dever do "artista" notar onde há (ou haverá) convergência ou necessidades dos vários sistemas se integrarem. Projetar aplicações já prevendo possíveis integrações é uma ótima e difícil tarefa.

Eis o problema.... (integração via Tabelas Corporativas)
Numa empresa Xyz (empresa de três letrinhas http://blog.fragmental.com.br/2007/06/07/3-letrinhas/) o parque de sistemas conta com aproximadamente 8 grandes sistemas.

Sistema 1 - Recursos Humanos (S1)
Sistema 2 - Capacitação dos Recursos Humanos (S2)
...

O S1 trata do domínio de recursos humanos da empresa, nele há uma tabela corporativa denominada rh_pf para manter informações das várias pessoas fisícas. O S2 no momento de analise percebeu que existiria um conceito de aluno que necessitaria de uma validação (+ que isso um pouco de inteligência) de dados contidos no S1, logo prevendo uma integração futura às aplicações os projetistas tiveram a idéia de usar a mesma tabela [rh_pf] para se resolver este "pequeno problema". (1º tiveram que entender o esquema rh_pf)
Com essa solução houveram outros problemas, quando alguém fosse gerenciar os alunos existentes teria que realizar uma consulta a rh_pf... e agora? voltam todos os registros? {informações sigilosas não podem ser mostradas} E quando fosse alterar, outro sistema iria ter o direito de alterar dados que não pertencem ao contexto do mesmo?!
E as "ligações obrigatórias" {leia-se constraints} contidas em rh_pf como ficariam?

E os projetistas...
Sugeriram outra solução, criar uma coluna na tabela rh_pf chamada sistema, onde poderia se "controlar" quem é dono desses dados, e para as "ligações obrigatórias" resolveram tirar tal integridade (nesse momento o S1 - RH é informado que deverá realizar a verificação da integridade na própria aplicação... mais mudanças...).

Conseqüências...
Dor de cabeça, tempo gasto com outros projetos....
Um ano se passa e outro sistema S3 é obrigado a integrar-se {suas regras de negócio possivelmente necessitam de serviços de outros sistemas}... E a bola de neve cresce...
A computação neste local começou a se tornar centralizada. Se houver um desejo de mudança da tabela rh_pf com certeza vários sistemas irão ter que ser modificados. {Acoplação Extrema entre Sistemas}

Um possível solução
Uma solução seria cada um [dos sistemas] disponibilizar seus serviços... e os demais sistemas aproveitarem esses serviços. Novos sistemas poderiam utilizar os serviços já existentes para desenvolvimento dos mesmos. {conceito próximo a arquitetura S.O.A.}

Conclusão
Algo que eu, particularmente, percebo e que integrar sistemas "via tabelas corporativas" não parece uma boa solução pois os diversos sistemas se tornam muito dependentes uns dos outros, se grandes sistemas [como o dos correios] em uso já descobriram que centralizar não é um bom negócio e que distribuir tem mostrado melhores resultados, pra que centralizar?. [Alias essa é a afirmação da qual deu o título ao post]