A ciência da agilidade.

March 6th, 2010 agnaldo4j No comments

Olá,

Ultimamente tenho observado muitas discussões sobre usar Scrum ou Extreme Programming ou até mesmo fazer o que vem sendo chamado de Scrum-butt, que acredito ser lamentável, pois usam o modismo não a ciência para entender os motivos pelos quais o framework tem que ser usado como um todo para dar certo, pois ele deve ser a base para a auto-organização, emergência de padrões, melhoria contínua, remoção de impedimentos e assim alcançar a hiper-produtividade dita como possível, Scrum não ensina como fazer, mas oferece o ambiente necessário para se descobrir como fazer.

O framework Scrum tem sua origem no estudo de várias áreas  como: sistemas complexos adaptativos, redes de livre escala, teoria do caos, gerenciamento do conhecimento, gerenciamento da incerteza e etc. Isso mostra que LEAN, Scrum e Extreme Programming são na verdade parceiras, sua formação vem da mesma linha de estudos, não são auto-exclusivas, ao contrário se usadas juntas se tornam mais fortes.

Hoje a empresa onde trabalho esta passando por uma reestruturação, estão organizando um modelo que não é popularmente conhecido como ágil, mas consigo ver neste sistema complexo, que é a empresa, a auto-organização e a emergência de algumas práticas que estão de acordo com a linha evolutiva que chegou ao Scrum, Extreme Programming e LEAN, percebo que se não houver o estado de negação, o caminho para aceitação do framework é algo inevitável e a melhoria do que se diz ágil também.

O vídeo  abaixo reforça o conceito das áreas de estudo necessárias para se entender as origens da agilidade.

Jeff Sutherland – Auto-Organização from Fabio Akita on Vimeo.

 

Aqui mais alguns videos sobre Frustração, Desordem e Complexidade

 

Para fechar uma explicação sobre caos

 

Espero com isso contribuir para discussões mais profundas e com isso ajudar a evoluir o que hoje chamamos de ágil.

Também espero que com discussões baseadas em fatos não em modismos, possamos esclarecer as dúvidas que todos temos, e de forma clara, usar o resultado destes entendimentos em nosso trabalho.

SoftSimples.com

É possível manter o time motivado, mas não é para amadores!

February 27th, 2010 agnaldo4j No comments

Sempre me pergunto, como é possível manter um time de desenvolvedores de software motivado, alguns dizem que não é possível, outros dizem que é possível, e então qual é a resposta?

A minha resposta é: sim é possível, mas não é para líderes que conhecem somente a superficie do gerenciamento ágil.

A hiper-produtividade é para os estudiosos, motivados e comprometidos, que procuram entender a ciência por trás de cada prática. Este entendimento leva a corrigir erros de aplicação de métodos. Erros que se não forem encarados de forma adequada, levam bons times a desmotivação e ao fracasso.

Esta palestra mostra um pouco mais abaixo da superficie.

SoftSimples.com

SCRUM: Na prática o que importa são os valores. from Danilo Bardusco on Vimeo.

SSWebframework + Behaviour Driven Development + Domain Driven Design – Sprint 2

February 27th, 2010 agnaldo4j No comments

Como falamos no último post, removemos o suporte a OSGI e melhoramos um pouco o suporte a maven adicionando um plugin para análise  de código e testes.

Também preparamos o serviço de persistência para ser o mais desacoplado possível, isso foi decidido em uma conversa com o Flávio W. Brasil, nós estavamos tentando fazer o mais simples possível, mas como esta conversa mostrou, estavamos cometendo o erro de acoplar fortemente os objetos de dominio com a técnologia de persistência.

Bom, agora temos que realmente fazer este serviço de persistência funcionar, para isso decidimos usar Behaviour Driven Development para nos guiar neste desenvolvimento e de todos as outros que virão, já falamos um pouco sobre Behaviour Driven Development em um post anterior, o motivo de adicionar este modelo de testes é usar conceitos de Domain Driven Design para reforçarmos um modelo de comunicação entre as pessoas que participam do projeto e mesmo para pessoas que venham a usar este projeto como referência para outros fins. Outro objetivo é melhorar o conhecimento de Domain Driven Design e Behaviour Driven Development para usá-los efetivamente no desenvolvimento de produtos que rodarão sobre o framework, o objetivo real de todo este trabalho.

Também podem encontrar informações sobre Behaviour Driven Development neste post.

OBS: todo o código comentado aqui pode ser encontrado no repositório do framework.

Até o próximo.

SoftSimples.com

SSWebframework + OSGI + MongoDB – Sprint 1

February 22nd, 2010 agnaldo4j No comments

Nesta última semana trabalhamos no desenvolvimento da primeira fase da modificação do framework para ter suporte a OSGI e MongoDB.

Ficamos felizes com o resultado apresentado pela estrutura do MongoDB,  não temos mais que nos preocupar com instalação de base, manutenção de schema de banco, mapeamento de objeto relacional, gerenciamento de dependências(jars)  e o código fica menor, casa muito bem com o framework já que este usa como protocolo padrão JSON para receber e responder as requisições feitas pelo lado cliente da aplicação, ou seja gerou um valor notável para nosso desenvolvimento.

Não ficamos felizes com os resultados do uso do OSGI, isso aumentou a complexibilidade e não ganhamos velocidade, não digo que OSGI é ruim, longe disso, digo apenas que para nossas necessidades atuais OSGI não gerou o valor que esperávamos.

Como nosso tempo de desenvolvimento é curto, temos que seguir a filosofia de remover do processo tudo que não gera valor real, e o framework não é nosso produto final, ele é apenas uma ferramenta para simplificar e acelerar o desenvolvimento dos produtos futuros que realmente são nosso objetivo.

Desta forma o próximo desenvolvimento será a remoção do suporte a OSGI e a reestruturação do projeto SSAdmin para ser um módulo do framework com suporte a MongoDB.

Para entender os motivos de nossa decisão, você pode achar útil ler o livro Getting Real, dar uma olhada em  LEAN ou assista o vídeo abaixo.

SoftSimples.com

Categories: Agile, Java Tags: , , , , ,

SSWEbframework + OSGI + MONGODB

February 11th, 2010 agnaldo4j No comments

Estou trabalhando na reestruturação do SSWebframework para ter um runtime dirigido por OSGI, isso tornará padrão o desenvolvimento dos bundles para o SSWebframework.

Também neste primeiro momento criaremos um bundle de persistência para mongodb, minha intenção é no futuro ter bundles de persistência também para couchdbobjeto relacional (hibernate).

Em um segundo momento pretendo mudar a forma de mapeamento dos controllers, pois hoje estou fazendo isso de uma forma precária mas que atende as necessidades, tanto é que já tenho sistemas rodando sobre essa plataforma, mas existem APIs como RESTEasy que parecem fazer o trabalho de forma mais elegante por isso o entusiasmo de migrar para esse modelo.

Também é necessário criar uma forma de manter as dependências do sistema sem ter que ficar mantendo xmls ridículos e depender de repositórios desatualizados ou pior ainda ter que montar um repositório de dependências, pretendo algo simples que utilize a estrutura de servidor que já possuo, que guarde minhas dependências na versão que quero e de forma simples. Por que quero isso? por que tenho esse poder, não quero e nem preciso depender de estruturas complexas para um trabalho que no meu caso ainda é simples.

Também posso criar no IDE que uso um bundle para recuperar estas dependências, esse bundle teria uma configuração visual, buscaria as dependências e acertaria o IDE deixando a casa pronta para para o desenvolvimento, a configuração deste bundle seria guardada junto com os fontes do projeto assim outro desenvolvedor no momento da abertura de seu IDE este bundle trabalharia para deixar tudo em ordem para ele começar seu desenvolvimento.

Isso tem impacto direto na integração continua, pois os integradores continuos usam estes xmls para fazer seu trabalho, isso será um problema que terei, mas espero achar um que pense de uma forma diferente e que não dependa de xmls, preciso de um que aponte para meu repositório de fontes e faça o que tem que fazer via padronizações e poucas configurações, espero também que este integrador continuo deixe eu criar bundles para realizar mais trabalhos que precisam ser feitos durante o processo de integração.

Bom, é um trabalho duro mas de aprendizado garantido, no final saberei se realmente sou obrigado ou não a me render as complexibilidades impostas.

SoftSimples.com

Categories: Agile, Java Tags: , , ,

Behavior Driven Development _pt_BR.properties

November 25th, 2009 agnaldo4j No comments

Olá,

Estudando Ruby nestes últimos dias, assisti um screencast que falava sobre o uso de Behavior Driven Development, para criar os testes de uma aplicação escrita em ruby, este screencast fala dos frameworks RSpec e cucumber e  é um ótimo início para quem quer usar este modo de testar suas aplicações.

Eu já tinha escutado sobre Behavior Driven Development antes, porém nunca tinha dado a devida atenção,  então como vi e ouvi mais uma vez que o Behavior Driven Development realmente me servia, inicieai as buscas por uma versão de RSpec ou cucumber para Java, de forma que eu fizesse meus testes da mesma forma, então descobri o JBehave.

Quando assisti este screencast eu estava procurando uma forma de testar o framework web que estou desenvolvendo, isso me mostrou um caminho interessante de como fazer estes testes de uma forma mais clara, que me guiasse pelas funcionalidades que eu espero ter e não me perder em coisas não tão importantes, mantendo o objetivo enquanto escrevo meu software, também queria que estes testes  servissem como documentação tanto para outros desenvolvedores como para pessoas não ligadas diretamente ao desenvolvimento, de forma a ter uma documentação viva, os cenários são isso.

Para tornar a comunicação destes cenários mais forte, decidi usar o JBehave escrevendo cenários em portugês, então iniciei meus estudos que acabaram gerando este projeto BDD_estudos usando a IDE Eclipse.

Este é o cenário de exemplo que foi base para todo o desenvolvimento do projeto BDD_estudos.

Dado que eu nao estou logado
Quando eu logar como Agnaldo e com a senha teste
Entao eu queria ver a mansagem "Bem-vindo, Agnaldo!"

Este assunto ainda não acabou, pois agora vem a parte mais interessante, realmente usar Behavior Driven Development para fazer os testes do framework web que estou desenvolvendo, mas isso fica para uma próxima.

Valeu, até.

Categories: Agile, Java, Ruby Tags: , , , ,

A hístoria da agilidade

November 12th, 2009 agnaldo4j No comments

Entendendo de onde vem os princípios ágeis tão falados hoje em dia.

Tão importante quanto seguir uma metodologia é conhecer sua filosofia.

Categories: Agile Tags: , , ,

Reforçando a comunicação e o comprometimento com Kanban

November 12th, 2009 agnaldo4j No comments

Há duas semanas tivemos que trabalhar em um desenvolvimento, daqueles que todo desenvolvedor sonha. :-)

1. Pouco tempo para desenvolvimento.

2. Negócio complicado.

3. Cliente aguardando para homologação deste e de outros itens(Não podiamos quebrar o build pois atrasaria a homologação).

Inicialmente pensamos que com 8 dias para desenvolver, criar testes e garantir qualidade , seria inevitável trabalhar no final de semana, já que haviam várias tarefas encontradas em uma análise superficial e ainda tinhamos algumas analises por fazer.

Para organizarmos estas tarefas, decidimos usar um kanban.

quadro de atividades

quadro de atividades

Usando essa ferramenta conseguimos manter uma boa comunicação, foco na solução dos problemas, entrega com testes e garantia de qualidade.

Se você tem dúvidas do que é o kanban dê uma olhada nesta apresentação.

Categories: Agile Tags: , , , ,

Assinando documentos xml

November 12th, 2009 agnaldo4j 2 comments

Continuando com o assunto de criptografia, vou passar um modelo de como fazer assinatura de documentos xml(Nota Fiscal Eletrônica), para isso vou usar a classe mostrada no post anterior.

Código:

package com.softsimples.crypto;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class AssinadorDeXML  {
	private XMLSignatureFactory signatureFactory;
	private DigestMethod digestMethod;
	private Transform transform;
	private Transform c14NTransform;
	private List<Transform> listOfTransforms;
	private final String c14NTransformStr = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
	private final GerenciadorDeKeystore gerenciadorDeKeystore;

	public AssinadorDeXML(GerenciadorDeKeystore gerenciadorDeKeystore) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, InvalidAlgorithmParameterException {
		this.gerenciadorDeKeystore = gerenciadorDeKeystore;
		this.listOfTransforms = new ArrayList<Transform>();
		this.signatureFactory = XMLSignatureFactory.getInstance("DOM");
		this.digestMethod = this.signatureFactory.newDigestMethod(DigestMethod.SHA1, null);
		this.transform = this.signatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec)null);
		this.c14NTransform = this.signatureFactory.newTransform(c14NTransformStr, (TransformParameterSpec)null);
		this.listOfTransforms.add(this.transform);
		this.listOfTransforms.add(this.c14NTransform);
	}

	public void criarAssinaturaParaXML(Document document, String strReference) throws KeyStoreException, SAXException, IOException, ParserConfigurationException, UnrecoverableKeyException, NoSuchAlgorithmException, MarshalException, XMLSignatureException, TransformerException, InvalidAlgorithmParameterException {
		Reference reference = this.signatureFactory.newReference(strReference, digestMethod, this.listOfTransforms,null, null);
		CanonicalizationMethod canonicalizationMethod = this.signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,(C14NMethodParameterSpec) null);
		SignatureMethod signatureMethod = this.signatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
		SignedInfo signedInfo = this.signatureFactory.newSignedInfo(canonicalizationMethod,signatureMethod,Collections.singletonList(reference));
		DOMSignContext signContext = new DOMSignContext(gerenciadorDeKeystore.getPrivateKey(), document.getDocumentElement());
		KeyInfo keyInfo = this.criarKeyInfo();
		this.assinar(signContext, signedInfo, keyInfo);
	}

	public boolean verificarAssinaturaDoXML(Document document) throws KeyStoreException, MarshalException, XMLSignatureException {
		Element element = document.getDocumentElement();
		NodeList listOfSignatureElement =  element.getElementsByTagName("Signature");
		if (listOfSignatureElement.getLength() == 0) throw new XMLSignatureException("Nao encontrado elemento de assinatura");
		Node signatureElement = listOfSignatureElement.item(0);
		DOMValidateContext validateContext = new DOMValidateContext(gerenciadorDeKeystore.getPublicKey(), signatureElement);
		XMLSignature signature = this.signatureFactory.unmarshalXMLSignature(validateContext);
		return signature.validate(validateContext);
	}

	public void assinar(DOMSignContext signContext, SignedInfo signedInfo, KeyInfo keyInfo) throws KeyStoreException, MarshalException, XMLSignatureException, TransformerException {
		XMLSignature signature = this.signatureFactory.newXMLSignature(signedInfo, keyInfo);
		signature.sign(signContext);
	}

	public KeyInfo criarKeyInfo() throws KeyStoreException {
		KeyInfoFactory keyInfoFactory = this.signatureFactory.getKeyInfoFactory();
		List<X509Certificate> x509Content = this.recuperarListaDeCertificados();
		X509Data x509Data = keyInfoFactory.newX509Data(x509Content);
		return keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
	}

	public List<X509Certificate> recuperarListaDeCertificados() throws KeyStoreException {
		X509Certificate certificate  = this.gerenciadorDeKeystore.getCertificado();
		List<X509Certificate> x509Content = new ArrayList<X509Certificate>();
		x509Content.add(certificate);
		return x509Content;
	}
}

Controlando cadeias de certificados

November 12th, 2009 agnaldo4j 2 comments

Este artigo é para desenvolvedores que precisam trabalhar com:

1. Conexão a webservices protegidos por cadeias de certificados digitais.

2. Controlar cadeias de certificados durante um processamento.

3. Trabalhar com tokens  PKCS11.

4. Trabalhar com certificados PKCS12 fornecidos por orgãos como SERASA (E-CPF,  E-CNPJ).

Antes de começar.

Para realizar os procedimentos deste artigo é necessário fazer o download do pacote Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy do site da sun, com este pacote podemos trabalhar com certificados do tipo PKCS12, PKCS11.

Existe também uma ferramenta para  importar/exportar certificados, criar keystores e assinar arquivos, que serão muito úteis para os testes que serão feitos durante o desenvolvimento do seu software e até mesmo criar seus próprios certificados para seus clientes se um certificado raiz não for necessário.

Código.

package com.softsimples.crypto;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class GerenciadorDeKeystore  {
	private static final String PKCS11 = "PKCS11";
	private final KeyStore keyStore;
	private final char[] pwdKeystoreCliente;
	private final File arquivoKeystoreCliente;
	private String aliasKeystoreCliente;
	private final String tipoKeystoreCliente;
	private final File arquivoKeystoreServidor;
	private final char[] pwdKeystoreServidor;
	private final String tipoKeystoreServidor;

	public GerenciadorDeKeystore(String tipoKeystoreCliente, File arquivoKeysotreCliente, String aliasKeystoreCliente,
									 char[] pwdKeystoreCliente, String tipoKeystoreServidor, File arquivoKeystoreServidor,
									 char[] pwdKeystoreServidor) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {

		this.tipoKeystoreCliente     = tipoKeystoreCliente;
		this.arquivoKeystoreCliente  = arquivoKeysotreCliente;
		this.aliasKeystoreCliente    = aliasKeystoreCliente;
		this.pwdKeystoreCliente      = pwdKeystoreCliente;
		this.tipoKeystoreServidor    = tipoKeystoreServidor;
		this.arquivoKeystoreServidor = arquivoKeystoreServidor;
		this.pwdKeystoreServidor     = pwdKeystoreServidor;

		this.keyStore = carregarKeystore(this.tipoKeystoreCliente, this.pwdKeystoreCliente, this.arquivoKeystoreCliente);
	}

	private KeyStore carregarKeystore(String type, char[] pwd, File arquivo) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
		KeyStore store = null;
		if (type.equalsIgnoreCase(PKCS11)) {
			Provider p = new sun.security.pkcs11.SunPKCS11("pkcs11.cfg");
			Security.addProvider(p);
			store = KeyStore.getInstance(type);
			store.load(null, pwd);
			this.aliasKeystoreCliente = store.aliases().nextElement();
		} else {
			store = KeyStore.getInstance(type);
			store.load(new FileInputStream(arquivo), pwd);
		}
		return store;
	}

	public X509Certificate getCertificado() throws KeyStoreException {
		return (X509Certificate)this.keyStore.getCertificate(this.aliasKeystoreCliente);
	}

	public PrivateKey getPrivateKey() throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException {
		Key key = this.keyStore.getKey(this.aliasKeystoreCliente, pwdKeystoreCliente);
        return (key instanceof PrivateKey) ? (PrivateKey)key : null;
	}

	public PublicKey getPublicKey() throws KeyStoreException {
		Certificate certificate = this.getCertificado();
		return certificate.getPublicKey();
	}

	public void configurarConexaoSegura() {
		System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
		Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

		System.setProperty("javax.net.ssl.trustStoreType", this.tipoKeystoreServidor);
		System.setProperty("javax.net.ssl.trustStore", this.arquivoKeystoreServidor.getAbsolutePath());
		System.setProperty("javax.net.ssl.trustStorePassword", String.valueOf(this.pwdKeystoreServidor));

		if (tipoKeystoreCliente.equalsIgnoreCase(PKCS11)) {
			System.setProperty("javax.net.ssl.keyStore", "NONE");
			System.setProperty("javax.net.ssl.keyStoreType", this.tipoKeystoreCliente);
			System.setProperty("javax.net.ssl.keyStoreProvider", "SunPKCS11-NFe");
			System.setProperty("javax.net.ssl.keyStoreAlias", this.aliasKeystoreCliente);
			System.setProperty("javax.net.ssl.keyStorePassword", String.valueOf(this.pwdKeystoreCliente));
		} else {
			System.setProperty("javax.net.ssl.keyStoreType", this.tipoKeystoreCliente);
			System.setProperty("javax.net.ssl.keyStore", this.arquivoKeystoreCliente.getAbsolutePath());
			System.setProperty("javax.net.ssl.keyStorePassword", String.valueOf(this.pwdKeystoreCliente));
		}
	}
}