Dapper

Tenho utilizado nos últimos meses o Dapper como ORM, substituindo o NHibernate nos meus projetos profissionais e pessoais. Não pretendo explicar a origem do Dapper ou os motivos para utilizar um ORM e sim exemplificar o uso do Dapper.

Libs utilizadas

Para nosso exemplo, iremos criar uma entidade chamada Montadora

public class Montadora
{
  public int Id { get; set; }

  public string Nome { get; set; }

  public string PaisOrigem { get; set; }
}

Esta entidade será mantida pela tabela Montadora

CREATE TABLE [dbo].[Montadora] (
    [Id]         NUMERIC(10) IDENTITY(1,1),
    [Nome]       NCHAR (30) NULL,
    [PaisOrigem] NCHAR (30) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
)

A manutenção dos dados será realizado pela classe MontadoraRepositorio

public class MontadoraRepositorio : IMontadoraRepositorio
{

  public string ConnectionString = ConfigurationManager.ConnectionStrings["DbSample"].ConnectionString;

  public IEnumerable<Montadora> GetAll()
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Query<Montadora>("SELECT Id ,Nome ,PaisOrigem FROM Montadora");

	  return data;
	}
  }

  public bool Insert(Montadora montadora)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Execute("insert into Montadora (Id, Nome, PaisOrigem) values(@Id, @Nome, @PaisOrigem)",
							new {Id = montadora.Id, Nome = montadora.Nome, PaisOrigem = montadora.PaisOrigem});

	  return data > 0;
	}
  }

  public bool Update(Montadora montadora)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Execute("update Montadora set Nome = @Nome, PaisOrigem = @PaisOrigem where Id = @Id",
							new {montadora.Nome, montadora.PaisOrigem, montadora.Id});

	  return data > 0;
	}
  }

  public bool Delete(int id)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Execute("delete from Montadora where Id = @Id", new {Id = id});

	  return data > 0;
	}
  }

  public Montadora Get(int id)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Query<Montadora>("SELECT Id ,Nome ,PaisOrigem FROM Montadora where Id = @Id", new {Id = id}).FirstOrDefault();

	  return data;
	}
  }
}

Detalhes a serem observados no repositório é que não precisamos realizar o mapeamento da nossa consulta para o objeto, o Dapper realiza todo o trabalho árduo.

A passagem de parâmetros para os comandos de insert, delete e updade é feita através de um objeto anônimo, deste modo, se as colunas possuírem a mesma estrutura de nomes da classes, basta passar os valores.

 

Até então, só utilizamos o Dapper, agora mostrarei a utilização do Dapper.Contrib que consegue deixar o desenvolvimento ainda mais simples.

public class MontadoraContribRepositorio : IMontadoraRepositorio
{
  public string ConnectionString = ConfigurationManager.ConnectionStrings["DbSample"].ConnectionString;

  public IEnumerable<Montadora> GetAll()
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  return db.GetAll<Montadora>();
	}
  }

  public bool Insert(Montadora montadora)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Insert(montadora);

	  return data > 0;
	}
  }

  public bool Update(Montadora montadora)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  return db.Update(montadora);
	}
  }

  public bool Delete(int id)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  return db.Delete(new Montadora() {Id = id});
	}
  }

  public Montadora Get(int id)
  {
	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  return db.Get<Montadora>(id);
	}
  }
}

Como podemos notar, com o Dapper.Contrib, não precisamos escrever nenhum comando SQL. Internamente ele já sabe o que precisa ser feito, mas para isto, precisamos realizar algumas alterações na nossa entidade

[Table("Montadora")]
public class Montadora
{
  [Key]
  public int Id { get; set; }

  public string Nome { get; set; }

  public string PaisOrigem { get; set; }
}

Um outro ponto importante é a necessidade da chave primária ser auto incremento, caso contrário, o Dapper irá gerar um erro de inclusão de NULL na pk da tabela.

O Dapper ainda permite realizar consultas para retorno de objetos mais complexos.

Para exemplificar, criei a entidade Carro que possui uma propriedade Montadora.

public class Carro
{
  [Key]
  public int Id { get; set; }

  public Montadora Montadora { get; set; }


  public string Nome { get; set; }

  public string Modelo { get; set; }

  public int AnoFabricacao { get; set; }
}

A tabela que representa esta entidade foi definida a seguir:

CREATE TABLE [dbo].[Carro] (
    [Id]            INT         NOT NULL,
    [Nome]          NCHAR (30)  NULL,
    [Modelo]        NCHAR (30)  NULL,
    [AnoFabricacao] NUMERIC (4) NULL,
    [MontadoraId]   INT         NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

E o repositório para consulta dos dados ficou assim:

public class CarroRepositorio
{
  public string ConnectionString = ConfigurationManager.ConnectionStrings["DbSample"].ConnectionString;

  public IEnumerable<Carro> GetAll()
  {

	var query = @"select Carro.Id, Carro.Nome, Carro.Modelo, Carro.AnoFabricacao, Carro.MontadoraId, Montadora.Nome, Montadora.PaisOrigem 
                            from 	Carro,	Montadora where Carro.MontadoraId = Montadora.Id";

	using (var db = new System.Data.SqlClient.SqlConnection(ConnectionString))
	{
	  var data = db.Query<Carro, Montadora, Carro>(query,
												   (carro, montadora) =>
												   {
													 carro.Montadora = montadora;
													 return carro;
												   }, null, null, true, "MontadoraId");

	  return data;
	}
  }

O Dapper possui ainda uma série de funcionalidades muito bem documentada nos seus repositórios como BulkInsert e BulkUpdate por exemplo.

O código criado neste post pode ser baixado no meu github.

Regra para inovação

Este não é um longo texto sobre inovação, até porque este é um assunto que venho estudando. Mas serve mais como um lembrete para que eu não esqueça destes itens. Tim Brown no seu livro Design Thinking diz:

[…] é necessário conceder a uma equipe criativa o tempo, o espaço e o orçamento para cometer erros.

[…]

é muito fácil especificar as regras para esta abordagem, mas muito difícil aplicá-las:

  1. As melhores ideias surgem quando o ecossistema organizacional como um todo – e não apenas seus designs e engenheiros, e com certeza não apenas a administração – tem espaço para experimentação.
  2. as pessoas mais expostas a fatores externos dinâmicos (novas tecnologias, mudanças na base de clientes, ameaças e oportunidades estratégicas) são as mais bem posicionadas para reagir e as mais motivadas para fazer isso.
  3. não se devem favorecer ideias com base em que as gerou. (Repita em voz alta)
  4. as ideias que criam um buzz devem ser favorecidas. Na verdade, as ideias devem gerar alguma agitação, ainda que sutil, antes de receber apoio organizacional.
  5. as habilidades de “jardinagem” da liderança sênior devem ser utilizadas para cultivar, aparar e colher ideias. Os administradores chamam isso de “tolerância ao risco”. Eu chamo de “a parte cima para baixa do processo”.
  6. Um propósito universal deve ser articulado de modo que a organização tenha um senso de direcionamento e os inovadores não sintam a necessidade de inovação constante.

Estes seis itens me lembrou a definição de uma funcionalidade com um gestor:

– vamos fazer a funcionalidade A e dependendo da procura por B, fazemos a B também.

– não, vamos fazer a B!

– mas e se ela não for procurada?

– ela vai ser. Tenho certeza!

O gestor, meses depois foi demitido, e ninguém conhece as funcionalidades citadas.

JavaScript. Tudo que você sempre quis saber e nunca teve coragem de perguntar

Aconteceu no dia 01/07 o segundo bate papo sobre tecnologia. Para o primeiro bate papo sobre o AWS, faltou malandragem nossa para transmitir ao vivo. Para o segundo, sobre javascript, conseguimos disponibilizar no Youtube. Os encontros vem acontecendo a cada duas semanas, sempre com assuntos variados.

Pontuar ou não pontuar, eis a questão

Constantemente eu me vejo a volta em discussões sobre a necessidade de pontuar uma história. Até que ponto faz sentido? Quais os ganhos? Isso é igual ao tempo necessário para desenvolver a história?

pontuar ou não pontuar

Para começar, a pontuação não corresponde ao tempo necessário para desenvolver uma história.

Os novatos tendem a acreditar que estes dois conceitos são iguais, mas a verdade é que a pontuação está relacionada a complexidade para trabalhar aquela história. O tempo necessário para desenvolver é definido pelas tarefas relacionadas as histórias e com isto, pode ocorrer de histórias com a mesma complexidade possuírem tempo de desenvolvimento diferente.

No entanto, com o tempo temos uma tendência a criar uma previsibilidade com relação ao tempo necessário para desenvolver histórias. A partir de uma base histórica, conseguiremos prever e estimar o tempo de desenvolvimento sem a necessidade de quebrar as histórias em tarefas.

Um outro benefício que muitas vezes não é percebido é o auxilio na priorização a partir do cálculo do ROI (Return of Investiment). Sabendo a complexidade de uma história, conseguiremos com a ajuda do PO (Product Owner) definir o quanto aquela história trará de retorno para o negócio.

Imaginemos um projeto com 5 histórias:

  1. Cadastro de Clientes
  2. Cadastro de Filmes
  3. Controle de Locação
  4. Cobrança de Locação
  5. Relatório de Locação

Após entendimento das histórias pelo time de desenvolvimento, temos as seguintes pontuações definidas pelo time de desenvolvimento:

História Pontos de Complexidade
Cadastro de Clientes 3
Cadastro de Filmes 3
Controle de Locação 5
Cobrança de Locação 5
Relatório de Locação 8

Tendo nosso projeto pontuado, pediremos para o nosso PO distribuir 100 unidade de valor entre estas histórias, onde a que for mais importante, receberá mais unidades de valor e a que tiver menos importância receberá menos unidades de valor.

História Pontos de Complexidade Valor para o PO
Cadastro de Clientes 3 15
Cadastro de Filmes 3 20
Controle de Locação 5 40
Cobrança de Locação 5 20
Relatório de Locação 8 5

Com base nos pontos de complexidade e nos valores distribuídos pelo PO, podemos realizar o cálculo do ROI e apoiar o PO na priorização do backlog com um simples cálculo:

ROI = Valor para o PO / Pontos de Complexidade

 

História Pontos de Complexidade Valor para o PO ROI
Controle de Locação 5 40 8,00
Cadastro de Clientes 3 20 6,67
Cadastro de Filmes 3 15 5,00
Cobrança de Locação 5 20 4,00
Relatório de Locação 8 5 0,62

Com a simples definição da pontuação das histórias, construímos com o passar do tempo uma base histórica que nos ajudará na previsibilidade de projetos futuros e  conseguimos priorizar o backlog de acordo com o retorno que cada história trará para o negócio.

Autenticação por 2 Fatores

Postado originalmente no Dicas-L
Autor: Paulo Kretcheu

Não sei se todos conhecem e/ou usam algum sistema que utilize autenticação por 2 fatores, eu tenho usado há algum tempo para a minha conta no gmail.

Funciona assim:

Os 2 fatores são

Uma coisa que você sabe: sua senha.
Uma coisa que você tem: seu celular.
Muito bem, eu configurei minha conta no Google para usar isso, lá você pode definir se quer receber um sms com um código ou usar um aplicativo para gerá-lo. Eu uso a segunda opção, pois instalei no meu Android o aplicativo para isso: Google Authenticator Há versões para outros sistemas móveis.

Esse código vale por um período pequeno de tempo, algo em torno de 1 minuto por padrão.

Então para logar na sua conta, por exemplo numa máquina que não é a sua, você irá digitar sua senha e depois o código que recebeu. Portanto mesmo que alguém tenha sua senha, vai precisar também do seu celular para saber o código, fica BEM mais difícil né!

Hoje usando meu velho e bom aptitude, vi que no Debian tem um pacote, nos repositórios oficiais, para usar o PAM com o Google Authenticator. Fiquei super interessado e comecei a fazer os testes.

Resumindo, para logar no meu servidor via ssh também estou usando autenticação por 2 fatores, a senha e o código.

Como fazer isso no Debian? É bem fácil!!

# aptitude install libpam-google-authenticator

No arquivo /etc/pam.d/sshd colocar logo no começo a linha:

auth required pam_google_authenticator.so

No arquivo /etc/ssh/sshd_config deve ter a linha:

ChallengeResponseAuthentication yes

Com seu usuário rode:

google-authenticator

Isso irá gerar uma chave, códigos de reserva e um arquivo no seu “home”, além de uma url para poder cadastrar no aplicativo do Android.

Basta reiniciar o serviço ssh

# /etc/init.d/ssh restart

Pronto, agora quando tento logar no ssh recebo a mensagem:

Verification code: XXXXXX
Password: XXXXXX

Cadastrei no meu Android e pronto!

Feito, sshd rodando com autenticação por 2 fatores.

Algumas dúvidas e algumas respostas:

  • Dá para fazer isso com outros serviços de autenticação também, sem ser o do Google?
    Sim, mas ainda não testei.
  • Dá para usar no gdm?
    Sim e em qualquer coisa que use PAM.
  • Dá para configurar para usar localmente sem os 2 fatores?
    Sim, mas também não fiz ainda.
  • O Google vai ficar sabendo quando você loga!
    Não! Não precisa de conexão a internet.
  • E se perder o celular?
    Tem os códigos de reserva. E a máquina também né! Acesso físico=sem segurança.
  • Se usar o home criptografado, também funciona?
    Eu li que sim, mas ainda não testei.

    Alguns links que podem ajudar:
    Google Authenticator
    Two Factor SSH with Google Authenticator

    Manual sobre “dados abertos”

    O escritório brasileiro do W3C publicou em parceria com a Transparência Hacker uma versão adaptada e traduzida do Open Data Manual.

    O manual reúne conceitos de “dados abertos” e informações técnicas (o que é API, XML, JSON).

    Na versão brasileira do manual, dicas de como organizar um “hackathon“, informações sobre como funcionam as leis federais de acesso a dados públicos, além de exemplos brasileiros de projetos de “dados abertos” e detalhes do primeiro Transparência Hack Day, em São Paulo.

    O documento é gratuito e pode ser baixado no site do W3C Brasil (em formato pdf).

     

    Fonte: Tiago Dória Weblog

    Nova Versão Ginga-NCL Virtual Set-top Box (v.0.12.3)

    Está disponível a nova versão do código aberto Ginga C++ (v.0.12.3), bem como do Ginga-NCL Virtual Set-top Box (v.0.12.3). Usuários de versões anteriores são fortemente recomendados a fazer a atualização.
    Dicas sobre como obter e compilar o Ginga C++ podem ser encontradas aqui: svn.softwarepublico.gov.br/trac/ginga/wiki/Building_Wiki_GingaNCL
    Entre as principais novidades da versão 0.12.3 estão:
    1) Sintonia de canais
    a. Suporte a canais RTP unicast e multicast foi implementado
    b. Suporte a definição de canais por um arquivo TS local mais estável
    2) Aderência às normas ITU-T e ABNT
    a. Suporte a apresentação distribuída (comunicação com dispositivos passivos e ativos)
    b. Suporte a transparência em objetos NCL embutidos em um documento NCL foi implementado
    c. Suporte a busca de objetos remotos por streaming (http e rtp) foi implementado
    d. Palavra reservada para transparência era tratada como opacidade. A funcionalidade foi atualizada para respeitar as normas. Agora, por exemplo, definir 30% de transparência significa que o objeto será apresentado com 70% de opacidade
    A lista completa de atualizações feitas no código pode ser encontrada no log dos projetos.
    Como vocês sabem, o Ginga-NCL Virtual Set-top Box é uma máquina virtual VMWare com sistema Linux instalado e pré-configurado com todos os requisitos do Ginga (C++). Pode ser obtido por meio da SubComunidade Ginga-NCL, no box “Direto ao Ginga”. Lá vocês encontram também um “HOW-TO” com dicas para instalar e operar o Ginga-NCL Virtual Set-top Box.
    Entre as principais novidades do Ginga-NCL Virtual Set-top Box está a nova resolução para simular dispositivos portáteis e o suporte a apresentação distribuída de um documento NCL (uma máquina virtual pode ser instanciada como base enquanto outras máquinas são instanciadas como dispositivos passivos ou ativos).
    Comentários, dúvidas e sugestões são muito bem-vindos e devem ser enviados por meio do fórum específico para discussões em torno do Virtual Set-top Box na Comunidade Ginga.
    Comunidade Ginga
    SubComunidade Ginga-NCL
    Divirtam-se!
    Administração Ginga