Páginas

quarta-feira, 9 de dezembro de 2015

Dez coisas que todo desenvolvedor deve saber

Olá, galera!

Hoje tive o prazer de participar de um hangout com meus antigos colegas de trabalho Leandro Magnani, Luiz Pais, Alexandre Costa (Magoo), Gabriel Vieira e Vinícius Tosta sobre coisas que todos os desenvolvedores devem saber.

Confira no vídeo abaixo.

[]'s


segunda-feira, 30 de novembro de 2015

Usando PowerShell para obter informações do AD

Hoje precisei acessar algumas informações do AD, e decidi usar o PowerShell para isso.

Eu precisava encontrar alguns usuários na rede, e vi que o comando Get-ADUser (https://technet.microsoft.com/en-us/library/ee617241.aspx) era exatamente o que eu precisava. Assim, abri um console do PowerShell, digitei o comando e erro!


O comando Get-ADUser não foi reconhecido. Bom, neste caso eu precisava fazer referência ao pacote onde ele faz parte, mas vi que antes disso eu precisava baixá-lo. Pesquisando na internet vi que se tratava do Remote Server Administration Tools for Windows 7 with Service Pack 1 (SP1). O link para download é este: https://www.microsoft.com/en-us/download/details.aspx?id=7887

Depois de baixar o pacote e instalar, é necessário ativá-lo como feature do Windows. Para isso, basta escolher a opção "Módulo do Active Directory para Windows PowerShell" (ou "Active Directory Module For Windows PowerShell").


Feito isso, basta importar o módulo activedirectory através do comand Import-Module activedirectory, e a partir daí usar os comandos. Abaixo está uma imagem de exemplo.


Obs. Sim, infelizmente o Windows está em português nesta máquina. Nem tudo é perfeito na vida.

[]'s

segunda-feira, 26 de outubro de 2015

Pérola arquitetônica

Aqui está um código que é uma verdadeira obra arquitetônica!


A montagem eu mesmo que fiz :-)
Bom, mas quais são os problemas com esse código?

Este código está aí para permitir que campos possuam máscara de dados. Até aí, é um requisito normal de qualquer sistema. O problema é a forma como está sendo feito. Eu verifiquei e existem várias máscaras que não estão sendo utilizadas. Um primeiro problema aqui é desempenho, pois esse script executa em toda página que é carregada, acessando elementos HTML pelo jQuery. É um código desnecessário e sem justificativa.

Agora conceitualmente, essas inúmeras máscaras, qual o significado delas dentro do sistema? Qual tipo de campo é formatado por 19 números sequenciais? Não há motivo para esse código existir. Seria necessário a associação com alguma regra do sistema para que elas fizessem sentido. Máscaras que têm sentido são, por exemplo, CPF (999.999.999-99) ou CEP (99999-999).

[]'s

quinta-feira, 22 de outubro de 2015

Exemplos de filtros no MongoDB (API C#)

Neste post vou demonstrar alguns exemplos simples de pesquisa no MongoDB utilizando a API .NET. Para o exemplo, eu vou considerar uma base local contendo a collection restaurants, a mesma que é usada na própria documentação do MongoDB. Além disso, vou construir uma tela Windows Forms.

A primeira coisa a ser feita é adicionar o MongoDB.Driver, e a melhor forma de fazer isso é através do Nuget. Basta selecionar a opção “Manage Nuget packages” ao se clicar com o botão direito em cima do projeto, no Solution Explorer. Como vemos na tela abaixo, basta preencher “MongoDB” na pesquisa que uma lista de pacotes é retornada. Note que se deve instalar o pacote MongoDB.Driver, tomando cuidado para não colocar a API antiga.


No nosso exemplo, faremos uma filtragem de restaurantes de acordo com vários parâmetros. Para isso, teremos uma ListBox para receber os resultados, uma combo para se escolher o filtro e um botão para executar a ação.

Esses filtros vamos carregar de forma dinâmica no exemplo, através de Reflection. Nosso critério será todos os métodos privados que sejam de instância (não sejam estáticos) e que cujo nome se inicie com “Filter”.

Para conectar na base do MongoDB, primeiro precisamos de um objeto do tipo MongoClient. Ele recebe como parâmetro a string de conexão, que no caso aponta para o MongoDB que eu tenho instalado na minha máquina. A partir desse objeto, usando o método GetDatabase nós obtemos uma referência a base que vamos trabalhar no MongoBD.

De forma a evitar repetição de código, eu criei um método genérico que recebe um objeto do tipo FilterDefinition e que obtém uma referência à collection que será pesquisada; executa a pesquisa passando o objeto FilterDefinition, obtendo uma lista através do método ToListAsync; e por fim formata essa lista resultante exibindo o nome, tipo de cozinha e localização. Este método é chamado ExecuteFilter.

O primeiro exemplo de filtro é do método FilterBrazilianRestaurants. Como o nome diz, ele faz a filtragem dos dados que trabalham com cozinha brasileira. O objeto filter é obtido a partir da classe Builders. Esse objeto possui um método Eq que cria uma cláusula de igualdade. No exemplo, serão procurados todos os registros que possuem o campo cuisine com valor Brazilian.

No método FilterBrazilianRestaurantsInManhattan as coisas começam a ficar interessantes. Veja que estamos juntando dois critérios de igualdade, com o operador &. Isso faz com que sejam pesquisados todos os registros com o campo cuisine igual a Brazilian e também todos que possuem o campo borough como Manhattan.

O terceiro método é o FilterBrazilianRestaurantsInManhattanOrDelicatessen, onde vemos um exemplo de como fazemos uma pesquisa usando o “ou”. Neste caso buscamos todos os restaurantes brasileiros em Manhattan ou todas as delicatessens. 

Até agora usamos somente o operador Eq, mas a API permite usar também operações de maior, menor, etc.

Por fim, temos o método FilterBrazilianRestaurantsNearCoord, onde vamos fazer um exemplo de pesquisa por localização. O método Near recebe um ponto (coordenada no globo terrestre), a distância máxima e mínima, e retorna todos os registros que estejam próximos considerando este critério. Mas para isso funcionar corretamente, é necessário criar um índice no MongoDB com o comando abaixo.

db.restaurants.createIndex( { "address.coord": "2dsphere" } )

Com isso, eu termino por aqui o exemplo. Até a próxima.

using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GeoJsonObjectModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MongoDBAPIExample
{
    public partial class Form1 : Form
    {
        private static IMongoClient _client;
        private static IMongoDatabase _database;

        public Form1()
        {
            InitializeComponent();
            _client = new MongoClient("mongodb://localhost:27017");
            _database = _client.GetDatabase("test");
            var methods = GetType().GetTypeInfo().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(m => m.Name.StartsWith("Filter"));
            foreach (var method in methods)
                comboBox1.Items.Add(method.Name);
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            var items = await (Task<List<string>>)GetType().GetTypeInfo()
                    .GetDeclaredMethod(comboBox1.SelectedItem.ToString())
                    .Invoke(this, null);
            listBox1.Items.Clear();
            foreach (var item in items)
            {
                listBox1.Items.Add(item);
            }
            label1.Text = string.Format("Total: {0}", items.Count);
        }

        private async Task<List<string>> ExecuteFilter(FilterDefinition<BsonDocument> filter)
        {
            var collection = _database.GetCollection<BsonDocument>("restaurants");
            var result = await collection.Find(filter).ToListAsync();
            return result.Select(i => string.Format("{0} ({1}) in {2}", i["name"], i["cuisine"], i["borough"])).ToList();
        }

        private async Task<List<string>> FilterBrazilianRestaurants()
        {
            var builder = Builders<BsonDocument>.Filter;
            var filter = builder.Eq("cuisine", "Brazilian");
            return await ExecuteFilter(filter);
        }

        private async Task<List<string>> FilterBrazilianRestaurantsInManhattan()
        {
            var builder = Builders<BsonDocument>.Filter;
            var filter = builder.Eq("cuisine", "Brazilian") & builder.Eq("borough", "Manhattan");
            return await ExecuteFilter(filter);
        }

        private async Task<List<string>> FilterBrazilianRestaurantsInManhattanOrDelicatessen()
        {
            var builder = Builders<BsonDocument>.Filter;
            var filter = (builder.Eq("cuisine", "Brazilian") & builder.Eq("borough", "Manhattan"))
                | builder.Eq("cuisine", "Delicatessen");
            return await ExecuteFilter(filter);
        }

        private async Task<List<string>> FilterBrazilianRestaurantsNearCoord()
        {
            double lat = -73.9617039999, lng = 40.6629420000;
            double maxDist = 1000, minDist = 10;
            var point = new GeoJsonPoint<geojson2dcoordinates>(new GeoJson2DCoordinates(lat, lng));
            var builder = Builders<BsonDocument>.Filter;
            var filter = builder.Eq("cuisine", "Brazilian") &
                builder.Near("address.coord", point, maxDist, minDist);
            return await ExecuteFilter(filter);
        }
    }
}

domingo, 16 de agosto de 2015

"Facades" na vida real



Muitos profissionais de TI possuem ou já possuíram empresas abertas para prestação de serviços, pois muitos lugares trabalham com essa forma de contratação terceirizada. Mas depois se a pessoa muda para um trabalho onde seja contratado como CLT, manter uma empresa aberta pode gerar gastos mensais com sua manutenção que são desnecessários.

Para uma pessoa encerrar uma empresa são necessários vários passos burocráticos. Envolvem a interação com vários órgãos como Previdência Social, Junta Comercial, Receita Federal, prefeituras, entre outros (este link possui um resumo caso você tenha curiosidade http://www.sebrae.com.br/sites/PortalSebrae/artigos/Como-fechar-uma-empresa:-passo-a-passo-para-encerrar-as-atividades).

Mesmo sendo possível uma pessoa enfrentar toda essa burocracia e fazer todo o processo de encerramento sozinha, é muito mais prático contratar alguém especializado para fazer esse trabalho. Geralmente o próprio contador que manteve a empresa ativa durante o tempo em que a pessoa esteve contratada como PJ (pessoa jurídica).

Dessa forma todo o trabalho é terceirizado e a pessoa não tem que se preocupar com os detalhes para o encerramento da empresa. Ela só precisa solicitar ao contador, passar as informações necessárias para que ele desempenhe o trabalho, e aguardar o seu retorno.

Mas o que isso tem a ver com este post? Não, eu não vou ensinar aqui como encerrar uma empresa muito menos fazer propaganda de consultorias de contabilidade. Esse exemplo que eu dei é para ilustrar como funciona o design pattern Facade.

Este padrão é utilizado para simplificar a interação de objetos, provendo uma interface mais enxuta de forma que toda a complexidade fique invisível ao cliente. Entretanto ele é muito mal utilizado pois os desenvolvedores geralmente têm um conceito deturpado dele.


Isso geralmente ocorre em lugares onde se estabelece uma determinada arquitetura de sistemas que divide os componentes em camadas de dados, camada de negócio e a famigerada camada de fachada (facade). O problema é que os sistemas são construídos de forma anêmica, ou seja, essas camadas não possuem inteligência e se resumem a “tubos” para comunicação de forma ineficiente entre a interface (tela) e a base de dados.

Veja a imagem abaixo. É um exemplo de um sistema construído da forma que eu citei. Veja que as camadas intermediárias não tem muita função a não ser repetir a mesma assinatura de método, ligando uma tela com o banco de dados, provavelmente com uma chamada de uma stored procedure. Na ânsia em se manter uma arquitetura que a empresa adota, muitas vezes não se pensa a real utilidade do que se está construindo.

Agora como esse sistema deveria ser, para utilizar corretamente um padrão de facade? Bom, temos que resolver o problema acima onde toda a lógica de manipulação ficou a cargo da tela (ela verifica se existe o pedido, emite a fatura e controla o envio de e-mail). O componente de facade então deve ser o único ponto da funcionalidade que se quer executar.


Perceba que no novo diagrama, a regra de negócio já foi para o meio e a tela faz uma única chamada. Toda orquestração (e sua complexidade) ficou então isolada a partir da fachada. Este componente então começa a "espalhar" chamadas para outros pontos do sistema.

Claro que ainda há espaço para muitas melhorias. Esse cenário que eu expus foi motivado pela manutenção de um sistema antigo, ainda usando Web Forms. Entretanto, a mensagem que eu gostaria de passar aqui é cuidado no uso de padrões, em especial o facade, para que não acabe deixando um sistema mais difícil de se manter.