Mais tarde eu postarei informações mais detalhadas, mas por enquanto, segue o placar final, em PDF.
PS: Eu sou do Boa Noite, e Bom Sort(); em 14º
Quod Erat Demonstrandum
Mais tarde eu postarei informações mais detalhadas, mas por enquanto, segue o placar final, em PDF.
PS: Eu sou do Boa Noite, e Bom Sort(); em 14º
Posted in No category.
– 25 de October de 2009
O Akita publicou recentemente um artigo traduzido sobre Os Problemas do Pensamento do Visual Studio (e outras IDEs) (Does Visual Studio Rot the Mind?, no original). Nele, ele ressalta diversos pontos onde os desenvolvedores podem perder a capacidade de pensar por desenvolverem no Visual Studio. Antes de qualquer coisa, digo que concordo com parte do que ele diz, mas vou tentar endereçar corretamente os pontos que ele levantou, para evitar qualquer tipo de injustiça ao .NET por culpa do Visual Studio.
Hoje (em Outubro de 2005), estamos prontos para o lançamento oficial do .NET Framework 2.0. Tabulando somente o MSCorLib.dll e aqueles assemblies que começam com a palavra System, temos mais de 5.000 classes públicas que incluem mais de 45.000 métodos públicos e 15.000 propriedades públicas, sem contar os métodos e propriedades herdados e não sobrescritos. Um livro que listasse os nomes, valores de retorno e argumentos destes métodos e propriedades, uma por linha, teria cerca de mil páginas.
Sim, o .NET realmente pode ter “5.000 classes públicas que incluem mais de 45.000 métodos públicos”. Mas isso chega realmente a ser um problema? Nessa estatística, ele inclui todos os assemblies que começam com System., além da MSCorLib.dll (o core do framework). Não chego a ver isso como uma real preocupação. Faz parte da idéia do Framework.NET ser abrangente, disponibilizando as bibliotecas para quem quiser usar, ou não. Eu, pessoalmente, não uso nada do System.Web.Extensions, por exemplo. E atualmente, muito pouco do System.Web per si.
Só para termos comparativos, o Ruby on Rails tem cerca de 2.000 classes e 10.000 métodos públicos, se somarmos a API do Ruby com a do Rails. Lembrando que o Ruby on Rails é apenas um framework web, não se propõe a fazer o que o System.Windows.Forms faz, por exemplo. Mas o eu quero discutir aqui não é o número de classes. É simplesmente mostrar que isso não importa tanto.
Visual Studio tem tentado atenuar o problema da proliferação de classes, métodos e propriedades com um recurso chamado IntelliSense. Isso certamente coloca a informação ao nosso alcance, se você pensar em seus dedos no sentido figurado como aquele lugar na tela onde o cursor do teclado está.
Como eu disse antes, não vejo o argumento anterior como um real problema. Na verdade, eu não consigo sequer ver a diferença entre algo que os programadores Ruby fazem muito
com algo que os programadores .NET fazem muito:
Nota do Akita: por isso é tão desconfortável exercitar Test Driven Development (TDD) com IDEs: TDD exige programação de cima para baixo, primeiro criando testes que falham para depois criar o código que a satisfaz. A IDE simplesmente não gosta dessa ordem e exige malabarismo para sair disso.
Nesse ponto devemos nos perguntar se a impossibilidade de fazer isso é do Visual Studio ou das linguagens estaticamente tipadas. A única coisa que o Visual Studio garante para você é que você seja indicado a escrever um código que compila. Ou seja, você não poder escrever “id” se o membro “id” não existe não é um problema do Visual Studio, mas uma característica das linguagens estaticamente tipadas. Não é o propósito aqui discutir isso.
Além do mais, se o objetivo é poder criar os testes antes de certos métodos existirem, o Visual Studio ainda ajuda a fazer isso numa static type fashion.
Além do que, não querendo me estender nessa discussão, a última ferramenta que eu me lembro que se dispos a fazer o desenvolvimento top-down ser mais fácil foi a UML, e não foi muito feliz no seu propósito.
Não só o Visual Studio tenta completar código que estamos digitando, mas há muitos anos, o Visual Studio quis gerar o código para nós. Se selecionarmos um novo projeto de tipo Aplicativo Windows, por exemplo, e dar-lhe um nome e um local em uma unidade de disco, o Visual Studio gerará código suficiente para que este projeto seja imediatamente compilável e executável.
E isso não é algo bom? O programador continua com a possibilidade de escrever ele mesmo o código de infra-estrutura do projeto, mas isso é algo tão repetitivo que não há porque fazê-lo. E não, não poderia ser omitido, pelo mesmo motivo que ele apresenta depois: alguém pode querer customizá-lo.
Agora há confusão, porque existem referências a DLLs que o programa realmente não precisa.
Realmente, mas isso só é problema para iniciantes que não entendem muito como funcionam as referências. Para quem tem experiência, basta remover essas referências. Um shift e um delete resolvem esse problema.
O Visual Studio também cria um arquivo chamado Form1.Designer.cs, e em algumas versões beta do Visual Studio 2005, esse arquivo não foi sequer listado entre os arquivos do projeto, por padrão. Este é o arquivo onde o Visual Studio insere código gerado quando você cria o formulário. O Visual Studio realmente não quer que você mexa com esse arquivo e por boas razões. Ele espera que este código gerado esteja em um determinado formato e, se você mexer nele, pode não ser capaz de lê-lo de volta na próxima vez que abrir o projeto.
Tomando o cuidado de ver esse arquivo, é fácil perceber que ele é bem simples e compreensível. Exatamente o que você faria se fosse escrever na mão (e sim, você ainda pode fazer isso!).
Na verdade, você pode até alterar na mão certas partes dele que não acontecem muitos problemas. Mas se você quer ainda gozar do editor visual, mas também quer poder mudar o comportamento de certos controles de forma avançada, existe o construtor da classe. Depois do famoso InitializeComponents(), você pode escrever código que customize o comportamento de alguns controles, sem passar pela interface de design.
Se você tentar ler este código, não é assim tão fácil, porque cada classe e estrutura é precedido por um namespace completo:
Ele faz isso para evitar usings desnecessários. Existe uma discussão filosófica em torno disso. O Visual Studio optou por uma delas. É um software de opinião, às vezes. Lembrando sempre que linguagens de programação não devem ser feitas com foco nas pessas que não sabem aprenderem rápido, e sim nas que sabem terem flexibilidade para fazet o que quiserem.
Os programadores realmente fazem isso? Eu tenho certeza que alguns fazem, mas também estou certo que muitos não o fazem. Como eu sei? Dê uma olhada em alguns dos códigos de exemplo que vem da Microsoft. Lá você verá button1, button2, button3, etc. E, no entanto, todos concordam que um dos elementos mais importantes de código auto-documentado está em dar nomes significativos às suas variáveis e objetos.
Então a solução é forçar os programadores a escrevem um nome? Não, eles devem escrever se acharem apropriado. Nada deve ser forçado, mas isso é a minha opinião.
Outro problema com a geração de código do Visual Studio é que todo controle vira uma propriedade na classe onde é criado. Esta é uma prática odiosa de programação, e realmente me incomoda que programadores possam estar olhando o código gerado pelo Visual Studio para aprender técnicas de programação adequada, e é isso que eles vêem.
Não vejo isso como algo ruim. Chama-se composição. Um form contém todos os controles que nele estão contidos. Faz sentido, não? Lembre-se que na orientação a objetos elas não se chamam variáveis globais, e sim atributos (ou campos). São parte do estado do objeto. Bem razoável, creio eu.
Ele reclama ainda sobre a memória gasta pelos objetos dos labels, textboxes, etc. E se pergunta se isso realmente precisaria estar na heap. Bem, eu acredito que cada componente deve ser um objeto. E como bom objeto, estar na heap. Se ele prefere que o form guarde TODAS as informações sobre si mesmo, sem objetos, recomendo que mude para uma linguagem menos orientada a objetos.
O texto termina falando sobre a filosofia de ter o código gerado numa black box ou não, se o seu código é puro ou não e coisa do gênero. Não creio que isso seja de bom tom atacar ou defender, pois isso é filosofia pessoal de cada um.
Fato é que, sem entender realmente o código, ninguém é bom programador. Seja o que programa .NET no Visual Studio ou o que programa Ruby no GEdit.
Posted in Development.
– 17 de September de 2009
Durante os testes com os diversos frameworks de migração, deparei-me com o Migrator.Net. Ele parecia ser bastante simples de usar, suportava vários databases, tinha integrações para o NAnt e o MSBuild, assim como uma interface console. Parecia perfeito, exceto por um motivo.
Uma migration com o Migrator.Net parece com isso:
using Migrator.Framework;
using System.Data;
[Migration(20080805151231)]
public class AddCustomerTable : Migration
{
public override void Up()
{
Database.AddTable("Customer",
new Column("name", DbType.String, 50),
new Column("address", DbType.String, 100),
new Column("age", DbType.Int32, 100),
new Column("profile_id", DbType.Int32);
);
Database.AddForeignKey("Customer_Profile_FK", "Customer", "profile_id", "Profile", "id");
}
public override void Down()
{
Database.RemoveTable("Customer");
}
}
Não chega a ser ruim. Mas qualquer pessoa que tenha conhecido as migrations do Rails (nesse ponto tenho que dar o braço a torcer) sabe que essa sintaxe não é boa.
Depois de escrever duas ou três migrations dessa forma, desisti e resolvi escrever minha própria API, baseando-me naquilo que aprendi com o Rails. Meu objetivo era chegar a algo assim:
using Migrator.Framework;
using System.Data;
[Migration(20080805151231)]
public class AddCustomerTable : Migration
{
public override void Up()
{
Schema.AddTable("Customers", t =>
{
t.AddString("name").WithSize(50);
t.AddString("address").WithSize(100);
t.AddInteger("age");
t.AddInteger("profile_id")
.AutoForeignKey("Profiles");
});
}
public override void Down()
{
Schema.RemoveTable("Customers");
}
}
Não há uma mudança drástica no código final da migration em si, mas o que me chamou a atenção durante o processo de desenvolvimento é que desenvolver interfaces fluentes afirma categoricamente o uso de orientação a objetos. Como o objetivo é que interface seja responsável por determinar certas ações a serem tomadas, acaba que cada objeto tem uma responsabilidade e só uma responsabilidade. E no final, o código acaba ficando mais coeso e conciso.
O diagrama de classes dessa nova API (que ainda está em desenvolvimento) mostra o quanto cada ação fica encapsulada dentro de sua classe específica.
O resultado disso tudo pode ser acompanhado em http://code.google.com/p/migratordotnet-fluent/.
Posted in Development.
– 13 de September de 2009
Não foi fácil, mas consegui terminar o mecanismo de serialização de lambda expressions pro Simple. Isso permitirá, sem problemas, sintaxes como:
Customer.List(x => x.ContactName == "Juan Lopes");
Não foi fácil, mas depois de pronto, é simples explicar.
O primeiro passo foi incorporar o MetaLinq ao projeto. Com ele, é possível transformar toda a árvore de Expressions em objetos específicos da biblioteca, e depois transformar de volta. O grande ganho é que esses objetos são serializaveis.
Uma pequena modificação precisou ser feita foi com relação aos atributos DataContract e DataMember, que não funcionaram muito bem no contexto do framework. Porém, foi só substituí-los por Serializable e tudo terminou bem.
Outro problema com o qual me deparei nos testes foi a possibilidade de uma expression tentar acessar objetos no seu contexto de criação. Digo, era impossível serializar uma expression como a abaixo, sem alguma modificação:
int x = 42; Product.List(p => p.QuantityInStock == x);
O problema acima é o fato da expression fazer referência à variável x. Sendo x uma constante, a primeira coisa que me veio à cabeça foi tentar fazer o eval dessa parte da árvore antes de enviar.
Percebi que o “x” dentro da Expression era renderizado como um MemberExpression, que acessava um membro dentro de uma ConstantExpression. O que fiz a priori (e que não funcionou muito bem) foi tentar fazer eval das MemberExpressions todas. O problema é que existem algumas expressions que dependem de ParameterExpressions, e não é possível fazer o eval delas.
Tive então que pesquisar um pouco mais. Descobri o termo “Funcletize”, que não tem muitas ocorrências no Google. A maior parte delas refere-se a um post na MSDN sobre o assunto, onde fala que a melhor forma de implementar Funcletization é por conta própria (apesar da Microsoft ter uma implementação – marcada como internal – disso no Linq2SQL).
Tendo visto isso, foi só procurar algum provider de Linq que já tivesse implementado Funcletization anteriormente. Com alguma busca, encontrei a classe Evaluator, no Linq2NH. Lá, eles chamam essa operação de PartialEval, onde eles substituem todos os ramos da árvore que não dependem de um parameter por uma ConstantExpression.
Com isso, tornou-se extremamente fácil serializar lambda expressions.
O resultado, você pode encontrar em
http://code.google.com/p/simpledotnet/source/browse/#svn/trunk/src/SimpleLib/Expressions
Posted in Development.
– 13 de September de 2009