Microservices vs SOA: entenda as diferenças

Palestra na FAPA
Palestra na FAPA

SOA ou Arquitetura Orientada a Serviços, na tradução literal, é um padrão que já existe tem algum tempo, usado principalmente por grandes corporações. Mais recentemente o mercado voltou a falar de outra arquitetura igualmente distribuída: microservices. Também não há nada de exatamente inovador em microservices, que estão aí desde a década de 60, mas que recentemente voltou a ganhar força como padrão a ser adotado em diversos sistemas, principalmente aqueles que usam de persistência poliglota. Então porque eu venho escrever hoje sobra microservices vs SOA?

Durante meus estudos recentes sobre micro serviços me deparei com a seguinte pergunta: qual a diferença entre microservices e SOA? Não estaríamos todos falando mais do mesmo? Não vou entrar no mérito de CORBA, uma vez que este é um conceito mais consolidado e que acredito tenha caído em desuso na última década, principalmente a versão “Microsoftniana” DCOM/COM+.

Para entender melhor as diferenças, vamos relembrar alguns conceitos importantes e esclarecer algumas coisas.

O que é SOA?

Uma arquitetura orientada à serviços não é algo exatamente difícil de entender quando você lê sua definição na Wikipedia: “funcionalidades implementadas pelas aplicações devem ser disponibilizadas através de serviços”. Esses serviços podem ser consumidos por outros serviços para que o todo forme um sistema complexo. É o clássico “dividir para conquistar”. No entanto, SOA não é tão simples assim, e foi nós desenvolvedores que o tornamos complicado demais.

Para algumas empresas, usar SOA é apenas expor software através de webservices. Dentro dessa concepção, há grupos mais conservadores que acreditam que isso inclui apenas os vários padrões WS-* e outros mais liberais que aceitam qualquer tipo de dado sobre HTTP (não necessariamente apenas XML). O que você acha, isso é SOA?

Para outras empresas, SOA implica em uma arquitetura em que não há UMA aplicação única que consome alguns serviços, mas sim que TUDO são serviços que fornecem desde dados a regras de negócio e que são agregados através de uma UI que consome todos eles. O que você acha, isso é SOA?

Não obstante, outras empresas acreditam que SOA é um jeito de permitir que diferentes sistemas se comuniquem através uma estrutura padrão com outras aplicações, assim como CORBA, mas usando XML. Isso geralmente inclui um barramento central de comunicação e dados que todos serviços usam para se organizar e centralizar a informação. Não necessariamente sobre HTTP, inclusive. O que você acha, isso é SOA?

Muitas empresas e desenvolvedores dizem coisas diferentes a respeito do que é SOA. Dizem que serve para separar dados de processos, dizem que é bom para combinar dados e processos, dizem que deve usar web standards, dizem que é independente de web standards, que síncrono, que é assíncrono, que sincronicidade não importa…muitas coisas diferentes e conflitantes!

Isto não é um problema exclusivo de SOA, temos esse mesmo problema de definição entre as diferentes tribos que usam POO. Você deve conhecer as velhas discussões sobre classes apenas com atributos ou apenas com métodos, serem ou não orientadas à objetos, só para citar um exemplo.

E os microservices?

Quando estamos construindo arquitetura de software focadas na comunicação entre diferentes serviços é comum acabarmos colocando muita responsabilidade e inteligência no mecanismo de comunicação propriamente dito. Um bom exemplo disso é o Enterprise Service Bus (ESB ou Barramento de Serviço Corporativo). Esse tipo de “produto” geralmente inclui recursos sofisticados como roteamento de mensagens, coreografia, transformação e aplicação de regras de negócio. E olha que ele deveria ser apenas um barramento de comunicação…

Mas e os microservices? O que eles propõem de diferente que valha a pena entender?

Microservices focam em endpoints inteligentes (os serviços) e canais de comunicação burros (protocolos simples, como REST). Aplicações construídas a partir de microservices possuem o objetivo (e a regra) de serem tão desacopladas e coesas quanto for possível. A “coreografia” entre elas se dá através de simples protocolos como REST ao invés de protocolos complicados como WS-Choreography ou BPEL ou ainda sendo orquestrado por uma ferramenta para isso.

Times trabalhando com microservices usam princípios e protocolos que a própria web usa, simplificando muito a curva de aprendizado e a arquitetura como um todo. Mesmo que se queira (ou se necessite) de um barramento de comunicação, ao invés de se adotar um ESB, usam-se barramentos leves de mensageria como RabbitMQ ou ZeroMQ, servindo apenas como filas confiáveis assíncronas para não se perder mensagens. Toda a inteligência fica no serviço, não no barramento.

O grande desafio dos times que querem trocar de padrão de arquitetura: monolítica para microservices é que o “normal” na indústria é que os componentes se comuniquem através de invocação de métodos ou chamadas de funções e é mudar esse padrão de comunicação que mora o grande desafio.

Microservices vs SOA

Não seriam os microservices a mesma coisa que SOA, mas algumas décadas atrás quando o padrão nasceu? Inclusive algumas empresas que dizem usar SOA programam-na da mesma forma que hoje chamamos de microservices e isso não é ruim. O grande problema de usar o termo SOA é o que mencionei no início desse artigo, onde SOA significa muitas coisas diferentes e até contraditórias para diferentes pessoas. Via de regra, geralmente o que se vê é SOA sendo usado para integrar diferentes aplicações monolíticas através de um ESB. Pronto, falei.

Sem julgamentos aqui, mas não dá pra comparar isso com microservices, principalmente considerando a complexidade do canal de comunicação. E não julgo principalmente porque quem advoga das melhores práticas de microservices são pessoas que trabalharam muitos anos em empresas com sistemas SOA e sabem do que estão falando, principalmente sobre a complexidade que isso se tornou.

Sendo assim, dizer que você usa microservices não é o mesmo que dizer que você usa SOA e vice-versa, para a maioria das pessoas. Sinceramente não me importo com o rótulo, e considerando a definição mais abstrata e geral de SOA, eu afirmaria que microservices é uma forma de SOA. Outros mais extremistas diriam que microservices é SOA feita do jeito certo, mas não sou tão arrogante assim.

Governança descentralizada

Tanto em microservices quanto em SOA temos algum nível de governança dos serviços. No entanto, em SOA, ela é mais centralizada.

Uma das consequências de governança centralizada é a tendência a se criar padrões em torno de uma única plataforma de tecnologia. A experiência mostra que esta abordagem é restritiva em demasia, uma vez que “nem todo problema é um prego e nem toda solução é um martelo”, como diria o ditado. Grandes empresas como ThoughtWorks acreditam que devemos sempre utilizar a ferramenta certa para cada trabalho, mas os grandes problemas são:

  • que as aplicações monolíticas não nos dão toda a liberdade que queremos para fazer isso;
  • e que o SOA tem padrões demais a serem seguidos, o que acaba engessando os serviços;

Ao quebrar os componentes de uma aplicação monolítica em serviços nós permitimos que cada um deles seja implementado em tecnologias diferentes e use persistências diferentes e talvez essa seja o maior atrativo de microservices. Claro, não é porque podemos fazer um sistema cheio de serviços poliglotas que você deve fazê-lo, mas você tem essa opção, quando necessário.

Times trabalhando com microservices preferem uma abordagem diferente para padrões: ao invés de definir um documento com padrões (como no caso do SOA), eles descobrem uma maneira de resolver um problema e o transformam em um componente ou serviço, que pode inclusive ser compartilhado com o mundo, como o rápido crescimento do repositório do NPM pode confirmar. Esta colaboração cria padrões emergentes como o uso de determinado ORM ou framework web, por exemplo. Com a transformação do Git em padrão de facto para controle de versão, práticas open-source tem se tornado mais e mais comuns nas empresas.

O Netflix é um bom exemplo de organização que segue esta filosofia (e que o faz com Node.js). Compartilhando componentes úteis e testados na “linha de frente” eles encorajam outros desenvolvedores a usarem os mesmos padrões ao mesmo tempo em que deixam a porta aberta para outras possibilidades.

O mindset de microservices não aceita overheads, como por exemplo, os contratos de serviço exigidos no SOA. Padrões como Tolerant ReaderConsumer-Driven Contracts são comuns de serem aplicados a microservices e muitas ferramentas foram criadas para automatizar o processo de testes dos serviços para se certificar que tudo está funcionando mesmo sem contratos – uma abordagem elegante para resolver o dilema YAGNI.

Talvez o apogeu da governança descentralizada seja o éto popularizado pela Amazon de “você cria, você mantém” (tradução livre de “you build it/you run it”). Os times são responsáveis por todos os aspectos do software que eles constroem incluindo mantê-lo no ar 24/7. Este nível de responsabilidade é definitivamente a norma que mais e mais empresas estão aplicando sobre seus times como o Netflix tem feito também. Afinal, nada pode ser mais motivador para fazer você focar na qualidade do projeto do que ser acordado às 03h da manhã por causa de bugs em produção, certo?

Gerenciamento descentralizado de dados

Novamente, é muito comum vermos implementações de SOA onde temos uma única base de dados centralizadora de tudo. Uma grande premissa é a de que todos os dados são da mesma empresa, logo são os mesmos em todos serviços. No entanto, isso não é 100% verdade.

A descentralização do gerenciamento de dados apresenta-se de diferentes maneiras e, em um nível mais abstrato, significa que o modelo conceitual de mundo é diferente entre os sistemas, logo não há porque juntá-los em um único banco. Quer um exemplo? Os dados de um cliente que um vendedor precisa saber são completamente diferentes do que alguém do suporte precisa enxergar, além disso, até mesmo o nome ‘cliente’ não faz sentido ser o mesmo em ambas visões do sistema.

Este problema é comum entre aplicações diferentes mas pode ocorrer mesmo dentro de uma única aplicação, principalmente quando ela é dividida em componentes separados. Um jeito útil de se pensar sobre isso é a noção de Bounded Context do DDD, que eu não vou entrar em detalhes aqui.

Assim como pensar sobre os modelos conceituais de dados nos leva a pensar que eles deveriam ser separados, usar microservices reforça, e muito, esse mindset. Enquanto aplicações monolíticas preferem bases únicas e centralizadoras por padrão, microservices preferem deixar que cada serviço escolha a melhor maneira de persistir os seus dados, seja com a mesma base de dados, a mesma tecnologia mas bases diferentes ou tecnologias completamente diferentes. Claro, você pode usar persistência poliglota em aplicações monolíticas (Abstract Factory está aí para isso), mas ela é mais comum em projetos com microservices.

A descentralização da responsabilidade pelos dados através dos micro serviços tem seus reveses, como gerenciar atualizações. A abordagem mais comum é criar transações, assim como em aplicações monolíticas, embora isso gere uma complexidade significativamente.

Bom, o meu intuito nunca foi dizer como você deve programar suas aplicações, se com SOA ou com microservices, mas espero ter jogado alguma luz ao assunto e ajudá-lo a entender as diferenças.

Concorda? Discorda? Deixe nos comentários!

Até a próxima.

Referências: muitas referências foram retiradas do site oficial do Martin Fowler, o meu guru de programação favorito. Inclusive a única imagem do artigo é do site dele.

 

Introdução à Arquitetura de Micro Serviços

Workshop IFRS
Workshop IFRS

Tem uns 2 anos que passei a ouvir falar de micro serviços (microservices) mas faz poucos meses que passei a me interessar realmente pelo tema, uma vez que comecei a estudar Node.js para uso em meus projetos.

Micro serviços é uma maneira particular de desenvolver aplicações de maneira que cada módulo do software é um serviço standalone cujo deploy e escala acontecem de maneira independentes da “aplicação principal” (não confundir com SOA). Enquanto na arquitetura tradicional de software, chamada monolítica, quebramos uma grande aplicação em bibliotecas, cujos objetos são utilizados in-process, em uma aplicação modular como proposta na arquitetura de microservices cada módulo recebe requisições, as processa e devolve ao seu requerente o resultado, geralmente via HTTP.

A ideia não é exatamente nova, é usada em ambientes Unix desde a década de 60, mas recentemente se tornou o epicentro de uma grande revolução na forma como as empresas estão desenvolvendo software ágil baseado em equipes enxutas responsáveis por componentes auto-suficientes.

Neste post irei abordar os conceitos, detalhes, vantagens, desvantagens e principais dúvidas dessa arquitetura, bem como porque ela está sendo tão utilizada atualmente e como começar a organizar suas aplicações orientadas dessa maneira.

Veremos neste artigo:

A motivação por trás dos micro serviços

Muitas são as buzzwords do mundo de desenvolvimento de software e esta me pareceu mais uma quando a ouvi pela primeira vez. Apesar do seu nome ser auto-explicativo, é interessante estudarmos os reais impactos que uma arquitetura composta por diferentes módulos conversando via um canal lightweight como HTTP pode causar na forma como programamos e nos resultados que obtemos com software.

Resumidamente, o estilo de arquitetura em microservices é uma abordagem de desenvolver uma única aplicação como uma suíte de pequenos serviços, cada um rodando o seu próprio processo e se comunicando através de protocolos leves, geralmente com APIs HTTP. Estes serviços são construídos em torno de necessidades de negócio e são implantados de maneira independente geralmente através de deploy automatizado (pelo menos em um cenário ideal deveria ser assim). Existe um gerenciamento centralizado mínimo destes serviços e cada um deles pode ser escrito em uma linguagem diferente e utilizando persistências de dados diferentes também.

Para entender melhor a motivação por trás de microservices vale relembrar como os projetos são programados hoje, geralmente em três grandes partes: um client-side com a interface do usuário, uma base de dados com as informações do sistema, e uma camada server-side com a lógica da aplicação. A camada server-side lida com as requisições do usuário, executa a lógica de negócio, retornar e atualiza dados da base e disponibiliza informações prontas para o client-side exibir. Isto é um monólito ou aplicação monolítica, uma vez que gera uma única e grande aplicação com tudo junto. Qualquer mudança no sistema envolve em compilar tudo novamente e implantar uma nova versão do server-side inteiro no servidor.

Toda a aplicação roda em um único processo, usando uma única linguagem server-side e geralmente uma única tecnologia de persistência de dados. Para escalar esse tipo de aplicação você pode adicionar mais recursos no mesmo servidor (escala vertical) ou fazer cópias desse servidor e colocá-las atrás de um load balancer (escala horizontal).

Aplicações monolíticas não são ruins e podem ser muitíssimo bem sucedidas. No entanto, cada vez mais equipes estão frustradas com suas limitações, principalmente quando estão implantando projetos na nuvem. Nestes cenários, os ciclos de mudanças, geralmente rápidos e pontuais como os propostos no Lean Startup, acabam afetando toda a aplicação pois o deploy é monolítico, assim como a aplicação. A escala horizontal requer um custo alto, pois sempre deve ser duplicada a aplicação inteira, e não apenas a parte que necessita de mais desempenho.

Vale lembrar também que aplicações monolíticas exigem que todo o codebase server-side seja escrito na mesma linguagem de programação, o que impede que você tire o máximo proveito de cada cenário usando a ferramenta mais apropriada à ele. Também impede que cada time desenvolva com a maior velocidade possível uma vez que a base de código é a mesma entre todos times.

Estas frustrações levam à arquitetura microservices de construir aplicações como um conjunto de serviços. Como os serviços são implantados de maneira independente, a escala se dá individualmente, tanto na vertical quanto na horizontal, para os serviços que estão precisando de mais desempenho. Usando protocolos comuns e contratos (interfaces) bem definidos, você consegue usar linguagens de programação diferentes de cada serviço, bem como mecanismos de persistência auxiliares que possam ser necessários para cada um deles, como mecanismos de cache, filas, índices, etc.

Para finalizar esta seção, a imagem abaixo do blog do Martin Fowler ilustra bem a diferença da escala entre as duas arquiteturas: monolítica e de micro serviços:

Vantagens e desvantagens de microservices

Não existe uma definição formal de como uma aplicação baseada em micro serviços deve ser construída, mas depois de muito ler a respeito e estudar o assunto notam-se algumas particuliaridades frequentes que podemos denominar como um padrão comum para microservices.

Sempre existiu o desejo dentro da indústria de software de construir programas apenas plugando componentes. Os primeiros esforços neste sentido foram as bibliotecas de funções, mais tarde as bibliotecas de classes e atualmente está em voga os serviços. Note que a componentização sempre existiu, mas o que propõe-se com microservices é que cada componente seja uma aplicação separada e especializada em apenas uma parte da aplicação “completa”. A principal razão por trás dessa escolha, de serviços ao invés de bibliotecas, é que serviços podem ser implantados de maneira separada. Você já tentou atualizar seu software apenas subindo para produção uma DLL ao invés de todas (ou ao menos todas as suas)? É um risco que não vale a pena correr, pois o acoplamento entre as DLLs é muito alto e o ideal é sempre a recompilação do sistema como um todo.

Claro, existe uma desvantagem clara no uso de serviços ao invés de bibliotecas: performance. Bibliotecas rodam no mesmo processo da aplicação, usam memória compartilhada, etc. Serviços dependem de canais de comunicação, como HTTP, para conseguirem tratar e responder as requisições. Exigem também uma coordenação entre os contratos de serviço para que os consumidores consigam “conversar” com os serviço da maneira que eles esperam, bem como receber as respostas que estão preparados.

Esse problema é especialmente preocupante conforme você tenha muitas chamadas síncronas entre seus serviços, pois o tempo de espera total para seu sistema responder será igual à soma de todos os tempos de espera das chamadas síncronas. Neste momento você tem duas opções: mudar para uma abordagem assíncrona ou reduzir o máximo que puder o tempo de espera (e a quantidade) das requisições síncronas. Node.js é uma tecnologia que tenho estudado bastante recentemente e trabalha muito forte com o conceito de chamada assíncronas, muito usado pelo Netflix para não bloquear a experiência do usuário. No entanto, quando isso não é possível, como foi o caso do site do jornal The Guardian, tente limitar o número de chamadas síncronas que você vai precisar, o que no caso deles é a regra de apenas uma chamada síncrona por requisição do usuário.

Apesar desses problemas citados, os benefícios parecem superar os downsides dessa abordagem, pois cada vez mais empresas estão adotando-na.

O que você deve ter em mente

Os serviços irão falhar. Talvez não todos juntos, talvez não rapidamente, mas vaia acontecer. Sendo assim, você deve estar sempre preparado para a falha de um ou mais serviços.

Essa é uma consequência de usar serviços como componentes e sua aplicação deve ser projetada de maneira que possa tolerar a falha de serviços. Qualquer chamado a um serviço pode falhar devido à indisponibilidade de um fornecedor e você tem de saber lidar com isso de maneira amigável com o restante do sistema. Esta talvez seja a maior desvantagem dessa arquitetura se comparada ao jeito monolítico tradicional, uma vez que adiciona uma complexidade adicional significativa. Times que trabalham com micro serviços devem constantemente refletir como a falha de cada serviço afetará a experiência do usuário. No Netflix por exemplo, partes da bateria de testes diária deles inclui derrubar servidores e até datacenters para ver como a aplicação se comporta nestas situações.

Uma aplicação em micro serviços deve ser monitorada em um nível muito superior ao de uma aplicação monolítica tradicional, uma vez que os serviços podem falhar a qualquer momento e se possível, restaurar o funcionamento completo automaticamente. Monitoramento em tempo real deve ser enfático no processo de desenvolvimento, implantação e operação dos serviços. Não que você não tenha de ter esse mesmo cuidado com aplicações monolíticas, mas apenas que com micro serviços isso não é uma opção.

O quão grande é/deve ser um micro serviço?

Uma pergunta bem comum e que cai como uma luva para o próprio nome da “arquitetura’ é: o quão grande deve ser um micro serviço?

Infelizmente o nome micro serviço nos leva a perder tempo demais pensando no que exatamente micro quer dizer. Diversas empresas, de Amazon a Netflix, usam micro serviços de variados tamanhos e não há um consenso sobre eles. Especificamente na Amazon, considerando que cada micro serviço é (e deve) ser tratado como um produto separado e tem seu próprio time (squad, na verdade), eles usam a regra Two Pizza Team: se o time precisa de mais de duas pizzas por refeição para se manter alimentado é porque está grande demais, o que significa não mais de que 12 pessoas. No outro extremo, os menores times recomendados pela Amazon possuem 6 pessoas, o que eu pessoalmente, em minhas experiências como Scrum Master, acredite ser o ideal (você ainda pode chamar meus times de Two Pizza Team considerando que todo mundo gosta de comer vários pedaços de pizza!).

Resumindo, embora não exista uma regra, podemos assumir que se você precisa de uma equipe de mais de 12 pessoas para desenvolver e manter um serviço (considerando tudo: programação, infra, testes, etc), ele está grande demais e você deveria quebrá-lo em serviços menores.

Como começar com micro serviços?

Projetos usando micro serviços geralmente não nascem assim do dia para a noite. O que nota-se na maioria das implementações bem sucedidas é que elas vieram de um design evolucionários, vendo a decomposição em serviços como uma ferramenta que vai aos poucos ajudando a quebrar uma aplicação monolítica que está com problemas de escala, qualidade, etc em diversos componentes menores.

Neste cenário, o maior desafio é saber como que o monólito irá ser quebrado em serviços. O quê deve ser agrupado em conjunto? O que deve estar separado? Quais bases de dados serão usadas por quais serviços?

Um dos princípios-chave por trás dessas decisões é o de deploy e escala independentes entre os serviços. Se dois serviços sempre tem de ser colocados em produção em conjunto, eles deveriam ser um serviço só. Agora se eu tenho um serviço cujas publicações acontecem sempre por causa de alterações pequenas em um dos seus módulos internos, esse módulo interno deveria ser transformado em um serviço per se.

O site do jornal britânico The Guardian é um bom exemplo de aplicação que foi projetada e construída como um monólito e que vem evoluindo na direção de micro serviços. O monólito ainda é o core do site, mas eles têm adicionado novas funcionalidades usando micro serviços que consomem a API do site principal. Esta abordagem é particularmente interessante pra eles principalmente nos casos de módulos temporários, como um hotsite para cobrir um evento esportivo.  Estes hotsites podem ser programados rapidamente na linguagem que for mais conveniente e jogados fora uma vez que não fazem mais sentido.

E aí, motivado para trabalhar com essa abordagem? Vamos trocar experiências nos comentários!

 

13 dicas e truques da linguagem C#

Junta uma dica daqui, outra dali, e voilá, seguem 12 dicas para aumentar sua produtividade enquanto programa usando a linguagem C#. Nada milagroso, mas apenas práticas muitas vezes pouco conhecidas para aumento de produtividade, redução de código e por aí vai. Muitas só funcionam a partir do Framework 3.5, mas acredito que nesta altura do campeonato ninguém deveria estar programando em 2.0 ou frameworks inferiores…

Neste artigo você vai ver:

  1. Operador ternário
  2. Operador Null-coalesce
  3. Inicializadores de objetos
  4. A diretiva using
  5. Apelidos para nomes de classe e namespaces muito grandes
  6. Tipos nullables
  7. Propriedades automáticas
  8. Inferência de tipos
  9. Expressões Lambda
  10. string.IsNullOrEmpty()
  11. Use os atalhos do Visual Studio
  12. Use os snippets de código
  13. Estude essa lista do StackOverflow

1. Operador Ternário ‘?’

Use-o com moderação ou ele prejudicará a legibilidade de seu código. Basicamente o operador ternário substitui um bloco if tradicional em uma única linha de código. Novidade? NOT! Operadores ternários existem na linguagem C desde a década de 70. Na prática funciona assim, imagine o seguinte bloco de código:

Você pode substituí-lo usando o operador ternário que funciona da seguinte forma (Questão) ? (Ação Positiva) : (Ação Negativa). Vamos ver o exemplo anterior usando operador ternário:

2. Operador Null-coalesce ‘??’

Quantas vezes você tem de testar se objetos são nulos em seu código? O operador null-coalesce pode vir a ser útil a você então. Considere o seguinte código:

Obviamente poderíamos reescrever usando o operador ternário:

Porém, usando o operador null-coalesce, conseguimos encurtar ainda mais o código (se o objeto do lado esquerdo é null, então ele retornará o valor do lado direito):

3. Inicializadores de Objetos

Cansado de perder várias linhas de código para ficar setando valores de propriedades? Ou então cansado de ficar escrevendo dezenas de sobrecargas de construtores? Os construtores auto-implementados que surgiram na versão 3.0 do C# resolvem seu problema e de quebra ainda melhoram a legibilidade de seu código. Primeiro vamos ver o jeito tradicional de inicializar um objeto:

E agora usando os inicializadores de objeto:

4. A diretiva ‘using’

Uma vez que você precisa alocar um objeto em memória um pouco mais pesado que o normal, como streams e arquivos de mídia, é importante que seja feito um controle mais rigoroso na hora de liberar a memória novamente, evitando problemas futuros. Ou seja, sempre temos de fazer três etapas: criamos o objeto, usamos ele e o descartamos. Isso pode ser ilustrado com o trecho de código abaixo:

A diretiva using permite comprimir o código anterior em:

A diretiva using somente pode ser utilizada em objetos que implementem a interface IDisposable.

5. Apelidos para nomes de classes e namespaces muito grandes

Nomes em C# podem se tornar muito longos. Se você está desenvolvendo algo para Microsoft Office, pode estar querendo abrir um processo do Word para criar um documento, o que cria objetos com namespaces enormes. O código abaixo, usando a diretiva using para criar um apelido de namespace ilustra outro uso deste canivete suíço da programação C#:

6. Tipos Nullables

Algumas vezes é necessário que suas variáveis possam conter valores nulos, mesmo quando é um simples inteiro. Isto ocorre com mais frequência quanto trabalhos com mapeamento objeto-relacional, pois na maioria dos bancos de dados sempre teremos tabelas com colunas que podem conter valores nulos. Para tornar um variável comum em uma variável que aceita null, basta adicionar um ‘?’ ao final do tipo e pronto!

Os nullable-types surgiram na versão 2.0 do framework e podem ser invocados das duas formas exibidas anteriormente.

7. Propriedades Automáticas

No C# 3.0 ganhamos as propriedades automáticas. Geralmente a maioria das propriedades das classes são apenas exposições de atributos privados ao restante do sistema. Dificilmente elas possuem alguma lógica ou verificação que realmente exija a criação de um atributo privado e de uma propriedade pública. Desta forma, para que ficar repetindo gets e sets sempre iguais, retornando o valor de um atributo privado?

Sendo assim, as propriedades automáticas vieram para agilizar a tarefa de criação de propriedades que nada mais fazem do que retornar ou receber valores. Vale salientar que em tempo de compilação vão ser gerados atributos privados para onde os valores dessas propriedades ficarão armazenados. Ou seja, não muda nada para o sistema, apenas para o programador.

O bloco de código anterior mostra o jeito antigo de fazer as coisas. O bloco seguinte mostra as propriedades automáticas:

Para quem acha que criar propriedades automáticas públicas é a mesma coisa que criar atributos públicos, está redondamente enganado. O método DataBind presente na maioria dos controles de exibição de dados somente efetua o Bind sobre propriedades públicas e nunca sobre atributos de classe. Desta forma, se pretende que sua classe possa ser exibida em controles deste tipo, é bom usar as propriedades corretamente.

8. Inferência de Tipos

Esta é outra dica que deve ser usada com cuidado. Eu particularmente uso apenas quando estou trabalhando com namespaces desconhecidos ou com LINQ e Lambda Expressions. Sendo o C# uma linguagem fortemente tipada, é natural que aja toda uma preocupação com escolher o melhor tipo para as variáveis e objetos que serão utilizadas. Da mesma forma, é importante conhecer os diversos tipos existentes quando se está manipulando métodos de terceiros. A inferência de tipos permite que você deixe de escrever o tradicional código:

Desta forma:

Peraí, igual no Javascript? NOT!

Mesmo com a inferência de tipos C# ainda é uma linguagem fortemente tipada e uma vez que a inferência esteja concluída (i.e. a variável recebeu um valor) o tipo de seu conteúdo jamais poderá ser alterado. Novamente, isto é apenas a nível de programação. Quando o compilador entra em ação, ele atribui os tipos corretos conforme a necessidade, nos poupando do trabalho de decorar os mais variados tipos e retornos de chamadas de métodos. O objeto do tipo inferido pode perfeitamente ser utilizado como um objeto normal, como o código a seguir nos mostra:

Mas então, qual o tipo de elencoSenior?

Bizarro não? Já imaginou ter de trabalhar com este tipo maluco? Muito mais fácil com inferência de tipos.

9. Expressões Lambda

Expressões Lambda são expressões de consulta feitas sobre coleções de dados de forma extremamente otimizada e simples, criando um poderosa ferramenta de produtividade. Por exemplo, se tivéssemos uma lista de 30 funcionários e quiséssemos saber todos os funcionários que possuem mais de 35 anos?

Tradicionalmente teríamos de fazer um laço para percorrer todos os elementos da lista comparando a idade de cada elemento e adicionando-os em uma outra fila à medida em que forem encontrados os funcionários mais velhos. Com Lambda, tal tarefa se restringe somente a:

10. string.IsNullOrEmpty()

Não necessariamente uma feature da linguagem, mas um método estático muito útil da classe string. Me impressiono como existem pessoas que não conhecem esta poderosa ferramenta para testar se strings estão nulas (null) ou vazias (“”). Segue exemplo de código;

11. Use os atalhos do Visual Studio

Sim, nada é mais produtivo do que saber usar sua IDE ao máximo e atalhos são uma boa parte disso. Seguem os que mais utilizo:

  • Ctrl + K + D: identa todo o seu código automaticamente;
  • Ctrl + K + C: comenta um bloco de linhas;
  • Ctrl + K + U: descomenta um bloco de linhas;
  • Ctrl + Shift + Arrow Up: durante a programação, volta um método que você estava navegando;
  • Ctrl + Shift + Arrow Down: durante a programação, avança um método que você estava navegando;
  • Ctrl + .: implementa o método/classe inexistente que você acabou de escrever;
  • Ctrl + M + O: esconde todas as regions da classe atual;
  • Ctrl + Shift + B: compila todos os projetos;
  • F5: manda depurar um projeto;
  • Ctrl + F5: manda executar um projeto;
  • F10: durante a depuração, avança uma linha;
  • F11: durante a depuração, avança uma linha entrando nos detalhes da mesma;

12. Use os snippets de código

Snippets são palavras encurtadas que quando usamos no Visual Studio (e outras IDEs), seguidas de um TAB, elas se transformam em estruturas de código completas. Experimente digitar os seguintes snippets seguido de TAB:

  • for: monta um laço for padrão;
  • if: monta uma estrutura if padrão;
  • ctor: monta um construtor vazio para a classe atual;
  • cw: chama um Console.WriteLine();
  • do: cria um bloco do/while;
  • equals: sobrescreve o método equals de Object;
  • foreach: monta um laço foreach padrão;
  • try: cria um bloco try/catch padrão;
  • while: cria um bloco while padrão;

13. Estude essa lista do StackOverflow

Sinceramente, uma hora que eu estiver com mais paciência eu dou um resumida nos principais pontos que tem lá no StackOverflow para aumentar sua produtividade com C#. Por enquanto dá uma olhada nesta lista completíssima que o pessoal reuniu por lá, tem muita coisa boa: http://stackoverflow.com/questions/9033/hidden-features-of-c

E aí, tem alguma dica que eu não cobri aqui no post?