A série de artigos sobre high-order functions e Linq gerou algumas conversas sobre as lambda expressions que utilizei. Ali, de bate pronto, tive dificuldades de explicar o conceito e percebi que ele não é tão trivial tanto para explicar, como para entender.

Então vou tentar apresentar de uma forma alternativa, mostrando a evolução da linguagem em direção às lambdas expressions.

No .Net framework 1.1 os delegates já existiam. Sua utilização prática, no entanto, era restrita aos eventos. Não que isto fosse uma restrição do framework, era mais uma questão de pouco conhecimento dos desenvolvedores mesmo.

Como expliquei no Brincando com C#, os delegates permitem que uma função seja passada como parâmetro ou retorno de outra função. Desta forma posso delegar parte do meu algoritmo para outra função.

Por exemplo, se tenho um método que transforma linhas de texto. Por algum motivo a regra de transformação pode variar. Para não precisar reescrever o método inteiro para cada situação, utilizo um delegate para isolar este trecho de código e poder reaproveitar todo o resto.

O passo-a-passo que a gente já conhece: Declara um delegate, cria um método que recebe o delegate como parâmetro, cria o método que “implementa” o delegate.

    public delegate string Parser(string line);

    public IEnumerable<string> ParseText(IEnumerable<string> text, Parser parser)
    {
        var lines = new List<string>();

        foreach (string line in text)
        {
           lines.Add(parser(line));
        }

        return lines;
    }

    private string RemoveSpaces(string line)
    {
        return line.Replace(" ", "");
    }

Utilização é simples, chama o Parser, mandando como parâmetro o RemoveSpaces.

    var parsedLines =  (List<string>) ParseText(lines, RemoveSpaces);

Anonymous methods

O .Net Framework 2.0 trouxe a novidade dos anonymous methods. O nome não podia ser mais específico, métodos anônimos são ... anônimos! Ou seja, sem nome. Não é necessário definir formalmente o método, posso simplesmente declará-lo localmente.

    var parsedLines = (List<string>) ParseText(lines, 
                                               delegate(string line)
                                               {
                                                   return line.Replace(" ", "");
                                               });

Sinceramente, para um método que deveria ser anônimo, ele é um método bem declarado e tem uma sintaxe verborrágica.

Vamos fazer um exercício para imaginar uma sintaxe um pouco mais simples, retirando tudo o que desnecessário nesta declaração. Na Figura marquei o que é inútil nesta declaração. A começar por definir o método como um delegate, já que a chamada do método espera um delegate isto é totalmente desnecessário. Tipificar o(s) parâmetro(s) também é desnecessário, pois a assinatura do método já foi declarada no delegate. Por último, o parêntesis que determina o início e o fim do método.

anonMethod

 

 

 

 

Vemos que seria possível definir uma sintaxe ainda mais simples do que os métodos anônimos. E é exatamente isto que foi feito para o .Net Framework 3.0, com as Lambdas expressions.

 

Lambda expressions

O .Net Framework 3.0 trouxe esta nova sintaxe para escrever métodos anônimos, mais concisa e mais legível. O exemplo canônico, e mais simples, das expressões lambdas, é o calculo de uma raiz quadrada:

lambda

 

 

A Figura mostra que à esquerda são declarados os parâmetros da expressão, à direita a expressão em si. Neste simples exemplo é definido o parâmetro de entrada x e a expressão é a multiplicação do parâmetro por ele mesmo, ou seja, a sua raiz quadrada.

    var parsedLines = (List<string>) ParseText( lines, line => line.Replace( " ", "" ) );

Nosso exemplo, utilizando uma expressão lambda no lugar do método anônimo, fica bem mais simples e limpo. Uma coisa que pode confundir é como o compilador sabe qual o tipo do parâmetro line? Elementar, a função espera um delegate, cuja assinatura recebe um parâmetro do tipo string, por inferência, o compilador percebe que o parâmetro é do tipo string. A IDE utiliza a mesma regra para oferecer o intellisense, como mostra a Figura.

intellisense

 

 

 

 

 

 

A sintaxe lambda é bem mais robusta e complexa do que mostram estes dois exemplos que fiz aqui. Ela aceita parâmetros com tipo definido, métodos sem parâmetros, entre outras coisas. Um guia mais completo da sintaxe pode ser encontrado aqui.

Espero ter ajudado um pouco na compreensão deste novo conceito do .Net Framework.

< Exemplos >

Outro dia sai do trabalho com uma cópia de um artigo do Alistair Cockburn, Hexagonal architecture, que fala sobre arquitetura de aplicações. Acabei em uma mesa de bar e o artigo incitou um debate sobre a necessidade de desenvolver aplicações que são agnósticas em relação ao Banco de dados, em outras palavras, aplicações que funcionam com diversos bancos de dados somente com alteração de configurações.

Para alguns na mesa isto é desnecessário, já que este não é um requisito real na grande maioria dos casos. São raros os exemplos de aplicações que foram migradas de um SGBD para outro e não é possível prever que isto vá acontecer um dia. Portanto, adicionar esta característica a aplicação seria adicionar complexidade desnecessariamente.

O problema não são os argumentos, mas sim o assunto. Ele é tão polêmico, quanto inútil. Pior que isto, nos distrai do que é realmente importante, como aconteceu nesta conversa que tive.

Eis a introdução do artigo, que iniciou todo o debate:

Create your application to work without either a UI or a database so you can run automated regression-tests against the application, work when the database becomes unavailable, and link applications together without any user involvement.

O negrito foi colocado propositalmente para destacar o assunto mais importante, que é ofuscado pela inútil discussão sobre banco de dados. Os principais requisitos da divisão de responsabilidades entre camadas e artefatos de uma aplicação são: Testabilidade e manutenibilidade.

A lógica de comunicação com o Banco de dados é complexa o suficiente para ser considerada uma responsabilidade que deve ser isolada e testada à parte. Mas isto já é feito pela camada de acesso a dado na velha conhecida arquitetura em três camadas.

Se eu consigo isolar e substituir esta camada por test double para poder testar as outras camadas sem precisar acessar o banco de dados meus já estão infinitamente melhores.

É possível testar uma aplicação sem isolá-la em pedaços menores. Na verdade isto é até desejável, são conhecidos como testes de aceitação, que testam cenários fim a fim, inclusive a persistência e leitura de dados no banco de dados. Todavia estes testes normalmente são pouco assertivos e consomem bastante tempo.

Um teste destes pode falhar por que: A UI não está correta, a regra de negócios está com defeito, o código de persistência está incorreto, a conexão de rede falhou, o tempo de resposta expirou, o dado no Banco de dados está incorreto, o Banco de dados está offline ou <preencha aqui o seu motivo favorito>. Ou seja, por qualquer motivo.

Além disto, a comunicação aplicação SGBD ainda é um pontos que mais consome tempo de execução, o que torna estes testes demorados.

Em suma, é desejável, senão necessário, conseguir testar minha aplicação sem precisar acessar o banco de dados a cada teste.

Mas se é possível substituir toda a camada de acesso a dados por uma falsa, ou um test double, então eu consigo substituir por outra que acesse outro repositório de dados. Então a propriedade “banco de dados agnóstica” vem de graça, ou a um custo muito baixo, como resultado da correta divisão de responsabilidades e do desacoplamento das camadas.

Agora como todas as decisões feitas na construção de um software, custos e benefícios devem ser avaliados. Faz algum tempo que eu acredito que testabilidade não é uma característica negociável, pois o custo de não tê-la é enorme e, mais dia menos dia, virá morder o seu calcanhar.

Depois de todo este trabalho chegamos ao ponto em que eu digo: Tudo isto é desnecessário porque o Linq já nos oferece as três high-order functions em sua implementação.

Calma, pequeno gafanhoto, muitas vezes o caminho é muito mais interessante que o destino em si.

Se eu simplesmente mostrasse estas funcionalidades do Linq tudo pareceria confuso e mágico. Agora, sabendo como funcionam as high-order functions, fica muito mais fácil de entender o que está acontecendo.

Como falei antes algumas pessoas acham a sintaxe Linq sexy, outros não gostam e tem dificuldade de ler o código. A boa notícia é que não é necessário utilizar aquela sintaxe. Nos exemplos abaixo vou utilizar a API do Linq, ao invés da sintaxe de query.

Filter

Veja como é fácil filtrar uma coleção de objetos utilizando o Linq:

    List<Cliente> clientesDoPara = clientes.Where(cliente => cliente.Estado.Equals("Pará"))
                                            .ToList();

Utilizando a sintaxe Linq:

    var clientesDoPara = (from cliente in clientes
                          where cliente.Estado.Equals("Pará")
                          select cliente).ToList();

Map

Para o map posso utilizar a função select, também sem problemas.

    var clientes = clientesCrm.Select(clienteCRM => new Cliente(string.Format("{0} {1}", 
                                                                              clienteCRM.FirstName, 
                                                                              clienteCRM.LastName)))
                              .ToList();

Uitlizando a sintaxe Linq:

    var clientes = (from clienteCRM in clientesCrm
                    select new Cliente(string.Format("{0} {1}",
                                                     clienteCRM.FirstName,
                                                     clienteCRM.LastName))
                   ).ToList();

Fold ou Reduce

Este é um pouco mais interessante. Out-of-the-box o Linq já oferece várias implementações específicas, por exemplo Sum, Max, Min. São todos especializações do Reduce. Ele também oferece o genérico, Aggregate, que aceita a função que realiza o fold. Em nosso exemplo o Sum não nos atende, precisamos somar a multiplicação de dois campos. O resultado ficaria assim:

    public double TotalAmount()
    {
        return lines.Aggregate<SalesLine, double>(0d, AcumulaTotalDaLinha);
    }

    private static double AcumulaTotalDaLinha(double total, SalesLine item)
    {
        return total + (item.Quantidade * item.Preco);
    }

Mas também posso refatorar meu código e passar o cálculo do total da linha para a própria linha, faz todo o sentido, por sinal, neste caso posso utilizar o Sum:

    public class SalesLine
    {
        public double Quantidade { get; set; }
        public double Preco { get; set; }

        public double Total()
        {
            return this.Quantidade * this.Preco;
        }
    }
        public double TotalAmount()
        {
            return lines.Select(line => line.Total())
                        .Sum();
        }
    }

Ou simplesmente:

    public double TotalAmount()
    {
        return lines.Sum(line => line.Total());
    }

Perfomance e escopo

Olhando para os exemplos desta série uma importante dúvida pode surgir: Mas eu preciso transformar TUDO em coleção antes realizar estas operações? Por exemplo, não seria mais performático realizar o filtro ao trazer a coleção do banco de dados ao invés de realizá-la na coleção? O mesmo pode se dizer da integração, é necessário trazer todos os dados, criar uma coleção para depois transformá-los?

Para responder isto é necessário diferenciar o que é Linq do que são implementações de Linq:

Linq é a .Net Language-integrated query, ou seja, a sintaxe, e a API, que permite realizar operações sobre objetos IEnumerable. “Apenas” isto.

Uma implementação de Linq implementa estas operações para um determinado escopo. A Microsoft lançou, junto com o Linq, algumas implementações:

  • Linq to objects – Permite realizar queries Linq em qualquer coleção do .Net framework que implementa o IEnumerable, como List ou Array. É o que estou utilizando neste exemplo e o que você vê na imensa maioria de exemplos na internet.
  • Linq to SQL – Permite realizar queries Linq em Banco de dados SQL Server. Para possibilitar isto ele realiza um mapeamento entre tabelas do banco de dados e objetos .Net. As queries realizadas nestes objetos são transformadas em comandos T-SQL e executados no Banco de dados, retornando objetos instanciados.
  • Linq to XML – Permite realizar queries Linq em arquivos XML. Para isto foi criada uma nova API de manipulação de XML, localizada em System.Xml.Linq

Além destes existem diversas implementações de Linq criadas por terceiros. Desde “brincadeiras” como o Linq to Flickr até implementações para ferramentas de ORM. Uma ótima leitura para quem quer entender melhor isto é a série do Frans Bouma sobre a implementação do Linq to LLBLGen.

Então, respondendo a pergunta original: Não, o Linq não é restrito a coleções de objetos .Net, você pode fazer as mesmas queries em um Banco de dados SQL Server, por exemplo.

Quanto a performance ela não depende do Linq mas da implementação. Eu posso fazer um Linq to AnySGBD que simplesmente traz todas as linhas da tabelas e realiza o filtro em .Net, certamente não será a implementação mais performática disponível :)

< Exemplos >

Antes de continuar falando sobre Linq vou apresentar como ficariam os outros dois exemplos típicos de High-order functions seguindo a estrutura do Filter.

Map

Uma função que dada uma coleção de objetos de um tipo, retorna uma coleção de objetos de outro tipo, realizando a transformação.

Um exemplo é a integração entre dois aplicativos. É normal que entidades comuns, como Cliente, co-existam nas duas aplicações. Também é normal que esta entidade seja exatamente igual nos dois aplicativos. Daí a necessidade de transformações quando os sistemas estiverem trocando informações, desde formato de data, até normalização de tabelas.

Neste caso, o cliente em um dos aplicativos tem nome e sobrenome, já no outro, existe somente o nome completo. Ao trocar informações esta transformação é necessária.

private List<Cliente> MapClientes(List<ClienteCrm> collection)
{
    List<Cliente> result = new List<Cliente>();

    foreach (var item in collection)
    {
        result.Add(new Cliente(string.Format("{0} {1}", item.FirstName, item.LastName)));
    }

    return result;
}

Não é necessário seguir passo-a-passo, pois já fizemos isto no primeiro post, com o Filter. Isolando as partes que não mudam, das mutáveis, tenho o seguinte método para mapear qualquer par de objetos:

public delegate TResult Transform<TSource, TResult>(TSource source);

public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> collection, 
    Transform<TSource, TResult> transform)
{
    List<TResult> result = new List<TResult>();

    foreach (var item in collection)
    {
        result.Add(transform(item));
    }

    return result;
}

O código que utiliza este método seria:

Cliente MapClienteCrmToCliente(ClienteCrm clienteCrm)
{
    return new Cliente(string.Format("{0} {1}",
    clienteCrm.FirstName,
    clienteCrm.LastName));
}

List<Cliente> clientes = (List<Cliente>) clientesCrm.Map<ClienteCrm, Cliente>(MapClienteCrmToCliente);

Fold ou Reduce

Uma função que processa uma coleção de objetos retornando um valor. Este processamento de alguma forma combina os objetos desta coleção para calcular o resultado final. A mais óbvia seria a somatória, dada uma lista de inteiros retorne a soma destes.

Outro exemplo simples, mas um pouco menos óbvio, seria calcular o valor total de uma venda, que é a soma dos valores totais de cada uma de suas linhas, que é a quantidade de produtos multiplicada pelo preço unitário. O código ficaria assim:

public class SalesOrder
{
    private List<SalesLine> lines = new List<SalesLine>();

    public IEnumerable<SalesLine> Lines
    {
        get
        {
            return lines;
        }
    }

    public double TotalAmount()
    {
        double total = 0;

        foreach (var item in lines)
        {
            total = total + (item.Quantidade * item.Preco);
        }

        return total;
    }
}

Seguindo o mesmo processo de sempre, eu teria um método Fold genérico:

public delegate TResult Acumulate<TSource, TResult>(TSource item, TResult initial);

public static TResult Fold<TSource, TResult>(this IEnumerable<TSource> collection, TResult initial, Acumulate<TSource, TResult> acumulate)
{
    TResult result = initial;

    foreach (var item in collection)
        result = acumulate(item, result);

    return result;
}

E sua utilização seria:

    public double TotalAmount()
    {
        return lines.Fold<SalesLine, double>(0d, AcumulaTotalDaLinha);
    }

    private static double AcumulaTotalDaLinha(SalesLine item, double total)
    {
        return total + (item.Quantidade * item.Preco);
    }

No final das contas esta seria a classe completa, com os três extension methods.

using System;
using System.Collections.Generic;
using System.Linq;

public static class HighOrderExtension
{
    public static IEnumerable<T> Filter<T>(this IEnumerable<T> collection, 
                                            Predicate<T> filter)
    {
        var result = from item in collection
                     where filter(item)
                     select item;

        return result.ToList<T>();
    }

    public delegate TResult Transform<TSource, TResult>(TSource source);

    public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> collection, 
                                                                Transform<TSource, TResult> transform)
    {
        List<TResult> result = new List<TResult>();

        foreach (var item in collection)
        {
            result.Add(transform(item));
        }

        return result;
    }

    public delegate TResult Acumulate<TSource, TResult>(TSource item, TResult initial);

    public static TResult Fold<TSource, TResult>(this IEnumerable<TSource> collection, TResult initial, Acumulate<TSource, TResult> acumulate)
    {
        TResult result = initial;

        foreach (var item in collection)
            result = acumulate(item, result);

        return result;
    }
}

Até a próxima.

< Exemplos >

 

Mudando o target do projeto de .Net framework 2.0 para 3.5 (veja multi-targeting support), já existe um ganho imediato: O namespace System já oferece o delegate System.Predicate<T>, portanto posso apagar o meu delegate e recompilar o código. Isto mostra a aproximação do C#, e do .Net framework, dos paradigmas da programação funcional.

Mas existem outras novidades que podemos utilizar.

Extension methods

Com ele podemos estender um tipo sem precisar alterar, ou herdar, este tipo. Bem interessante, apesar de não ajudar muito na legibilidade do seu código. Mas em alguns casos, pode ajudar bastante.

Por exemplo, uma funcionalidade de Filtro, como a nossa, pode ser utilizada por qualquer coleção que implementa IEnumerable. Por isto, podemos criar um Extension method para este tipo.

 Figura3

 

 

 

 

 

 

 

A lógica em si não muda nada, mas alguns detalhes o tornam um extension method. A primeira é a classe tem que ser estática. O método também precisa ser estático. A Figura mostra isto. O terceiro ponto é o modifier this no parâmetro collection. Ele indica que um objeto do tipo IEnumerable poderá chamar este método, como se ele pertencesse ao tipo. Veja como muda a sua utilização:

Chamada antiga:

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) Filter(clientes, ClienteResideNoPara);
}

Nova chamada:

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) clientes.Filter(ClienteResideNoPara);
}

Ao invés de enviar a coleção de clientes como parâmetro da função, o Filter torna uma função daquele tipo. Só para ilustrar, veja que posso utilizar este método em qualquer IEnumerable como, por exemplo, uma coleção de serviços instalados na máquin, do System.ServiceProcess

public void FilterServicesTest()
{
    List<ServiceController> servicos = (List<ServiceController>) ServiceController.GetServices()
                                                                                    .Filter(ServicosIniciados);
}

private bool ServicosIniciados(ServiceController controller)
{
    return controller.Status == ServiceControllerStatus.Running;
}

Lambda expressions

Em poucas palavras, as expressões lambda permitem definir uma função anônima, sem a necessidade de formalizar um método. Você pode ler um pouco mais aqui ou buscar na internet. A sintaxe de uma expressão bem simples é:

    x => x * x

No lado esquerdo do operador “=>” definem-se os parâmetros da função, neste caso o x, do lado direito, a função que mutiplica o x por ele mesmo, ou seja, sua raiz quadrada.

É possível utilizar expressões lambdas para simplificar a chamada do Filter. Até agora estávamos usando:

private bool ClienteResideNoPara(Cliente cliente)
{
    return cliente.Estado.Equals("Pará");
}

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) clientes.Filter(ClienteResideNoPara);
}

Ao invés de definir uma função que implementa o delegate, posso simplesmente passar uma lambda como parâmetro e dispensar o método ClienteResideNoPara:

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) clientes.Filter(x => x.Estado.Equals("Pará"));
}

O charme da sintaxe Linq

A sintaxe do Linq definitivamente é garbosa, dá um tom moderno ao código-fonte. Mas não é só isto. Um query Linq também pode nos poupar de utilizar alguns statements, como o foreach e o if.

public static IEnumerable<T> Filter<T>(this IEnumerable<T> collection, 
                                                                 Predicate<T> filter)
{
    var result = from item in collection
                 where filter(item)
                 select item;

     return result.ToList<T>();
}

Elegante, simples e expressivo.

A seguir vamos falar um pouco mais Linq.

< Exemplos >

Não tenho dúvidas de que o C# é a linguagem que melhor evoluiu nos últimos anos. No entanto, são tantas mudanças e novidades que às vezes fica difícil acompanhar e aplicá-las no dia-a-dia.

Por exemplo, desde o C# 2.0, a linguagem vem sendo influenciada por conceitos de linguagem funcional. Estas novidades têm impacto na forma como escrevemos nosso código, nos constructors que utilizamos. E isto não muda de um dia para outro.

Por isto resolvi fazer algumas brincadeiras com C# para mostrar novas possibilidades na forma de programar já oferecidas pela linguagem. Vou começar com C# 2.0, sem as novidades do 3.5 e depois evoluir os exemplos.

High order function é um conceito típico da programação funcional: São funções que recebem uma ou mais funções como parâmetro ou retornam uma função. Para explicar melhor vou implementar alguns exemplos clássicos de high order functions: Filter, Map e Fold.

Filter

Um filtro processa uma coleção de objetos, filtrando-a de acordo com uma regra de decisão. Vamos considerar um exemplo simples, mas funcional, preciso filtrar de uma coleção de clientes todos que residem no estado do Pará. A implementação mais simples para resolver este problema seria:

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    List<Cliente> resultado = new List<Cliente>();

    foreach (Cliente cliente in clientes)
    if (cliente.Estado.Equals("Para"))
        resultado.Add(cliente);

    return resultado;
}

No dia seguinte preciso filtrar todos os clientes cujo nome começa com “P”. Posso utilizar a velha técnica de reuso de código conhecida como Ctrl+C, Ctrl+V. Todavia, estamos aqui para escrever código de qualidade, então esta opção não é aceitável. Para tornar este método reutilizável, preciso identificar o que pode ser reaproveitado e o que deve ser mutável.

Figura2

 

 

 

 

 

 

Tudo que está rachurado é código necessário e repetido para qualquer filtro sobre um cliente. É preciso criar uma nova lista de clientes, iterar sobre a lista atual, adicionar os escolhidos na nova lista e retorná-la ao final. O único trecho que muda é o algoritmo de decisão se o cliente entra ou não na nova lista.

O problema é que este algoritmo é uma função, que retorna um boleano, ou seja, preciso de uma função high-order, que recebe como parâmetro uma função. A forma de fazer isto em C# é utilizando delegate. Delegates permitem a passagem de uma função, com uma determinada assinatura, para outra função. Então vou: Abstrair a lógica de filtro para uma nova função, chamada FiltraClientes, que recebe a lista de clientes e o delegate da função de decide se o cliente é filtrado ou não; Criar este delegate, que recebe um cliente e retorna um boleano; e abstrair a lógica de filtro em um método que segue a assinatura deste delegate. Veja como ficou:

delegate bool Predicate(Cliente cliente);

private bool ClienteResideNoPara(Cliente cliente)
{
    return cliente.Estado.Equals("Pará");
}

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return FilterClientes(clientes, ClienteResideNoPara);
}

private List<Cliente> FilterClientes(List<Cliente> clientes, Predicate filter)
{
    List<Cliente> resultado = new List<Cliente>();

    foreach (Cliente cliente in clientes)
        if (filter(cliente))
            resultado.Add(cliente);

    return resultado;
}

Para finalizar utilizo o generics e a interface IEnumerable para tornar tudo independente do tipo da coleção e do objeto, ou seja filtro qualquer coleção de objetos, não interessa o seu tipo.

delegate bool Predicate<T>(T item);

private bool ClienteResideNoPara(Cliente cliente)
{
    return cliente.Estado.Equals("Pará");
}

private List<Cliente> GetClientesDoPara(List<Cliente> clientes)
{
    return (List<Cliente>) Filter(clientes, ClienteResideNoPara);
}

private IEnumerable<T> Filter<T>(IEnumerable<T> collection, Predicate<T> filter)
{
    List<T> resultado = new List<T>();

    foreach (T item in collection)
        if (filter(item))
            resultado.Add(item);

    return resultado;
}

Na próxima vou fazer o mesmo exercício para o Map. Aguardem

< Exemplos >

Controle de versão / ALM

Se você é, ou deseja ser, usuário de subversion, este é um artigo interessante para atividades não tão básicas, porém desejadas.

Este artigo é genérico, sobre controle de versão. Um ótimo documento de como organizar e gerenciar suas branches.

O Time DevDiv é responsável pelo Team Foundation Server e com certeza seu maior cliente. Uma série de posts está apresentando como eles utilizam o TFS internamente. Por enquanto o foco é gerência de projetos, através do issue tracking. Este é o último post, mas vale ler todos.

Arquitetura

Mr. I.M. Right discorre sobre resilência de um aplicativo através de sua capacidade de auto-regeneração. Parece viagem, mas não é.

< Notícias >

Arquitetura

Rob Conery está publicando uma série de vídeos sobre o ASP.NET MVC do ponto de vista de quem está começando a trabalhar com o framework. A série já está na Parte 8, mas vale a pena assistir do início.

Greg Young está publicando uma série sobre Distributed DDD (Domain Driven Design), ou seja como distribuir sua aplicação, onde implementar as mensagens, etc.

Udi Dahan, desenvolvedor do NServiceBus, escreveu um excelente artigo sobre arquitetura e serviços de longa duração. Um caso real que resultou no desenvolvimento do NServiceBus.

Ferramentas

lançado o Json.Net 2.0, James Newton-King lista as novidades desta versão.

Linguagens

Depois a sessão de sobre a Spec# no ALT.net de Seattle parece que todos se apaixonaram por esta extensão do C# desenvolvida pelo Microsoft Research. Você ver o vídeo da apresentação aqui, ou ler Matthew Podwysocki explicando algumas de suas funcionalidades, ou ainda escutar a entrevista no Hanselminutes do “pai” da linguagem, Rustan Leino.

< Notícias >

UI / WPF

A Mindscape, empresa responsável pelo Lightspeed, lançou mais um produto: WPF Elements, para se juntar ao WPF Porperty grid em sua linha de controle de UI para WPF.

Nova versão do ASP.NET Dynamic data.


Cloud

TreeSharp, uma Biblioteca C# para acessar o S3, serviço de storage da Amazon.


REST

Rick Strahl ensina como configurar o WCF para ASP.NET Ajax e RESTfull services.


LINQ

Visual LINQ, para quem gosta de designers visuais.


Testes unitários

Lançado o xUnit.net 1.0. Ainda estou procurando entender qual o objetivo de YAUTF (Yet another Unit test framework).

Um AutoMocking container feito com o Unity.


ALM

Mingle 2.0 anunciado pela Thougth studios. Várias novidades.

Testes unitários

Scott Guthrie apresenta testes unitários para aplicações Silverlight


Arquitetura

O Enterprise library 4.0 está a caminho, o time de Patterns & Practices já liberou o primeiro CTP.

O mesmo time também liberou o Unity 1.0, framework de Dependency Injection.

Rocky Lhotka lançou o CSLA .Net versão 3.5. Algumas semanas atrás o autor deu uma entrevista para o Hanselminutes falando sobre acesso a dados.

< Notícias >