É muito comum quando os usuários trocam
documentos, querer saber quem foi o criador do documento e até mesmo
quem foi o último a fazer a alteração no conteúdo. Infelizmente, nem
todos têm a prática de registrar os seus dados no aplicativo, de forma
que todo documento gerado, será registrado com o usuário que
criou/alterou o documento. Vale ressaltar que isso não é uma
particularidade do LibreOffice; em outras suites de escritório existe o
mesmo recurso, mas a maioria dos usuários não usam.
Nessa dica, veja como é fácil fazer essa configuração
e como isso facilita o trabalho no dia a dia. Obviamente tem gente que
dirá que não usará esse recurso, pois não quer ser rastreado em caso de
erro, mas posso garantir que em informática, quando se trabalha em rede,
tudo se sabe.
Um exemplo de documento que foi gerado e não se sabe quem criou e muito menos quem alterou, veja:

Configurando o LibreOffice com os dados do usuário:
Acesse o menu FERRAMENTAS ▶ OPÇÕES
No
item LibreOffice, sub-item Dados do usuário, nos campos nome e
sobrenome, preencha os seus dados. Clique no botão OK para confirmar.

Pronto, a partir de agora todo documento criado em sua máquina ficará registrado o nome e sobrenome.
Para verificar as propriedades do documento, acesse no menu ARQUIVO ▶ PROPRIEDADES, aba GERAL.

Observe como é importante e produtivo você ver as informações das propriedades do documento:
-
É possível ver o Criador do arquivo, data e hora que foi criado;
-
É possível ver quem foi o último a modificar o arquivo, data e hora que foi modificado;
-
É possível ver a última impressão do arquivo, quem foi, data e hora da impressão;
Quer coisa melhor do que isso? Obter todas as informações na tela sem precisar incomodar o helpdesk.
Boa leitura!
*** Artigo de Eliane Domingos de Sousa
|
Um dos meus primeiros trabalhos com Drupal foi uma integração com
webservices de um sistema acadêmico. Foi assim que usei um node_save()
pela primeira vez. Em quatro anos de Drupal, usei esse método para criar
muitos tipos de nodes programaticamente e desde de então nada mudou
nesse processo:
$node = node_load($nid);
$node->field_ingredientes[LANGUAGE_NONE][0]['nid'] = $ingrediente;
$node->field_dificuldade[LANGUAGE_NONE][0]['value'] = 'fácil';
node_save($node);
Isso até agora. O módulo Entity API
chegou para nos dar inúmeras melhorias no núcleo do sistema de entities
do Drupal, como por exemplo, o CRUD. Também nos dá uma técnica muito
interessante para edição de nodes, que são um tipo de entity. Ao invés
de usarmos a versão acima, que é muito feia, totalmente procedural e
sujeita a bugs, podemos usar a classe EntityDrupalWrapper.
Com isso temos os fields como atributos do objeto node:
$node = new EntityDrupalWrapper('node', $nid);
// Nos campos multivalorados temos um array
$node->field_ingredientes[0]->set($ingrediente);
// Nos campos com apenas um valor fica mais simples
$node->field_dificuldade->set('facil');
$node->save();
Essa classe transforma os objetos do core em objetos reais e não
apenas um array mais bonitinho. Ou seja, agora podemos estender uma
entity e colocar nossos próprios métodos, apenas estendendo o
EntityDrupalWrapper:
class Receita extends EntityDrupalWrapper {
public function __construct($data = NULL, $info = array()) {
parent::__construct('node', $data, $info);
}
public function save() {
// algum código aqui
parent::save();
return;
}
}
$node = new Receita($nid);
$node->field_ingredientes[0]->set($ingrediente);
$node->field_dificuldade->set('dificil');
$node->save();
//Também podemos pegar os dados nesse formato
$dificuldade = $node->field_dificuldade->value();
Isso é muito legal, pois vemos o Drupal caminhando cada vez mais para
a orientação a objetos, nos permitindo interagir com o core de um modo
muito mais elegante. O EntityDrupalWrapper nos permite encapsular muito
mais que apenas nodes e nos dá muitos helpers para ajudar no
desenvolvimento.
Este artigo é apenas conceitual, para ilustrar as mudanças que estão vindo no Drupal 8. As boas praticas dizem para usarmos entity_metadata_wrapper para fazer essa instanciação em projetos.
Então, a apartir de agora esqueça o velho método de criar nodes programaticamente e entre nessa revolução também.
***
Artigo publicado originalmente no Drupal de Elite – http://drupaldeelite.com.br/blog/entitydrupalwrapper-e-o-drupal-orientado-objetos
|
Se você trabalha com desenvolvimento de software, por experiência
própria, deve saber que a única constante no processo de
desenvolvimento é a mudança.
Mas por que isso ocorre? Com o desenvolvimento tecnológico obtidos
nos últimos tempos a área da tecnologia da informação foi impactada por
dois fatores importantes:
- O aumento do tamanho e da complexidade dos sistemas de software;
- A redução do tempo e custo de desenvolvimento e manutenção do software.
Assim, os sistemas ficaram mais complexos e maiores e o tempo e o
orçamento para desenvolver tais sistemas diminuiu. E o negócio não pode
parar…
Um software é um produto que foi criado para atender uma necessidade
de negócio, e os requisitos de negócio mudam a todo instante com base
nas prioridades do mesmo, logo o software tem que ser alterado para dar
suporte a tais mudanças. Dessa forma, um software que não foi bem
projetado para dar suporte às constantes mudanças irá se tornar obsoleto
e não vai mais cumprir o seu objetivo afetando os negócios.
Então ‘o negócio’ é projetar um software que seja fácil de ajustar e
barato de manter. Parece simples não é mesmo? Tudo começa com a
definição da arquitetura de software a ser adotada. Uma das tarefas
fundamentais no processo de criação de um software é a definição da
arquitetura do projeto de software pois uma arquitetura consistente e
bem definida se torna fundamental para que o projeto seja implementado
com eficiência.
A arquitetura de software desempenha um papel fundamental para
gerenciar a complexidade inerente ao software a ser criado. Uma boa
arquitetura possibilita que um sistema satisfaça às exigências
principais de um projeto, tais como: desempenho, confiabilidade,
portabilidade, manutenibilidade, interoperabilidade e etc.
Uma má arquitetura simplesmente fará com que o software seja um fracasso.
O que é arquitetura de software ?
Existem muitas definições de arquitetura de software:
“Uma arquitetura de software envolve a descrição de
elementos arquiteturais dos quais os sistemas serão construídos,
interações entre esses elementos, padrões que guiam suas composições e
restrições sobre estes padrões”. GARLAN, 2000
“A arquitetura de software define o que é o sistema em termos de
componentes computacionais e os relacionamentos entre estes
componentes”. VAROTO, 2002
“A arquitetura de software de um sistema consiste na definição dos
componentes de software, suas propriedades externas, e seus
relacionamentos com outros softwares. O termo também se refere à
documentação da arquitetura de software do sistema. A documentação da
arquitetura do software facilita: a comunicação entre os stakeholders,
registra as decisões iniciais acerca do projeto de alto-nível, e permite
o reuso do projeto dos componentes e padrões entre projetos”. http://pt.wikipedia.org/wiki/Arquitetura_de_software, acessado em 2012
Obs: Stakeholder é qualquer pessoa ou organização
que tenha interesse, ou seja afetado pelo projeto. (Stake: interesse,
participação, risco / Holder: aquele que possui)
Assim, a arquitetura de um sistema deve definir os elementos que irão
compor o software. Tais elementos definem como o software é
particionado em pedaços menores e, assim, definem como o software é
entendido.
Como definir uma boa arquitetura?
Segundo o RUP – Rational Unified Process, a arquitetura de um
software envolve o conjunto de decisões que definem a organização do
sistema e devem cumprir os seguintes objetivos:
- Definir os elementos estruturais e suas interfaces de modo a estabelecer a composição do sistema;
- Estabelecer o comportamento pela colaboração entre estes elementos;
- Compor estes elementos estruturais e comportamentais em subsistemas (agregação).
Diversos fatores influenciam a definição da arquitetura como por exemplo:
- Arquitetura do hardware;
- Sistema operacional utilizado;
- Sistema Gerenciador de Banco de dados adotado;
- Protocolos de rede;
- A linguagem de programação;
- O ambiente de interface gráfica;
- As bibliotecas de funções disponíveis;
- Os sistemas legados envolvidos;
- As necessidades de desempenho, portabilidade, usabilidade, disponibilidade, etc;
- Documentação.
Levando em conta esses fatores e sendo bem objetivo e prático, como
podemos definir uma arquitetura básica que possa ser implementada em
sistemas de pequeno é médio porte?
Por onde começar?
Comece pelo começo…
1. Defina os requisitos do sistema
Definir de forma sistemática os requisitos do sistema envolvendo
todos os stackholders (interessados) no projeto de forma a ter o maior
número possível de requisitos definidos de forma clara e objetiva;
Os requisitos expressam as características e restrições do produto de
software do ponto de vista de satisfação das necessidades do usuário,
e, em geral independem da tecnologia empregada na construção da solução
sendo a parte mais crítica e propensa a erros no desenvolvimento de
software.
Requisitos são objetivos ou restrições estabelecidas por clientes e
usuários do sistema que definem as diversas propriedades do sistema. Os
requisitos de software são, obviamente, aqueles dentre os requisitos de
sistema que dizem respeito a propriedades do software.
A necessidade de se estabelecer os requisitos de maneira de forma
precisa é crítica na medida que o tamanho e a complexidade do software
aumentam. Os requisitos exercem influência uns sobre os outros. Por
exemplo, o requisito de que o software de ter grande portabilidade (por
exemplo, ser implementado em Java) pode implicar em que o requisito
desempenho não seja satisfeito (programas em Java são, em geral, mais
lentos).
Uma boa especificação de requisitos deve ser:
- Clara e não ambígua;
- Completa;
- Correta;
- Compreensível;
- Consistente;
- Concisa;
- Confiável;.De acordo com Farley, um documento de especificação de requisitos deve possui as seguintes seções:
- Visão geral do produto e sumário;
- Ambientes de desenvolvimento, operação e manutenção;
- Interfaces externas e fluxo de dados;
- Requisitos funcionais;
- Requisitos de desempenho;
- Tratamento de exceções;
- Prioridades de implementação;
- Antecipação de mudanças e extensões;
- Dicas e diretrizes de design;
- Critérios de aceitação;
- Índice remissivo;
- Glossário.
2. Definir uma ferramenta ORM
De forma geral, você pode escolher uma ferramenta ORM para ajudá-lo a
criar os objetos com base no seu domínio e a partir deles gerar o banco
de dados usado pela aplicação.
Existem dezenas de ferramentas ORMs disponíveis no mercado. Abaixo uma relação das mais importantes para a plataforma .NET:
(fonte: http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software)
- ADO.NET Entity Framework, included in .NET Framework 3.5 SP1 and above
- AgileFx, open source
- Base One Foundation Component Library, free or commercial
- Devart LinqConnect, commercial, an ORM solution for Oracle, MySQL, PostgreSQL, and SQLite
- Castle ActiveRecord, ActiveRecord for .NET, open source
- DatabaseObjects .NET, open source
- DataObjects.NET, commercial
- ECO, commercial but free use for up to 12 classes
- EntitySpaces, commercial
- Habanero, free open source enterprise application framework with a free code generating tool
- MyBatis, free open source, formerly named iBATIS
- iBATIS, free open source, maintained by ASF but now inactive.
- LINQ to SQL, included in .NET Framework 3.5
- LLBLGen Pro, commercial
- Neo, open source but now inactive.
- NHibernate, open source
- nHydrate, open source
- OpenAccess ORM, by Telerik free or commercial
- Persistor.NET, free or commercial
- Quick Objects, free or commercial
- Signum Framework, open source
- SubSonic, open source
- Symbiotic, by Frozen Elephant Inc.
- XPO, commercial, by DevExpress
3. Aplique a separação das responsabilidades ao seu projeto de software
A definição da separação em camadas estimula a organização da
arquitetura do sistema em um conjunto de camadas coesas com fraco
acoplamento entre elas onde cada camada possui um propósito bem
definido.
Principais camadas:
- UI(camada de apresentação): agrega as classes do sistema com as quais os usuários interagem;
- Negócio: mantém as classes do sistema responsáveis pelos serviços e regras do negócio;
- Dados: camada responsável pelo armazenamento e recuperação dos dados persistentes do sistema;
- Comunicação: responsável pela distribuição do sistema em várias máquinas.

Considerações:
- Seja explícito sobre como as camadas se comunicam entre si –
Permitir que todas as camadas em um aplicativo se comuniquem ou tenham
dependências sobre todas as outras camadas resultará em uma solução que é
mais difícil de entender e gerenciar;
- Use a abstração para implementar o acoplamento fraco entre as
camadas – Isto pode ser conseguido através da definição de componentes
de interface, tais como uma Facade com entradas e saídas bem conhecidos
que traduzem os pedidos para um formato compreendido por componentes no
interior da camada;
- Não misture tipos diferentes de componentes na mesma camada lógica –
Comece por identificar diferentes áreas de interesse e, em seguida
agrupe os componentes associados a cada área de interesse em camadas
lógicas. Por exemplo, a camada de interface do usuário não deve conter
componentes de processamento de negócios, mas deve conter componentes
usados para manipular a entrada do usuário e solicitações dos usuários
do processo;
- Mantenha o formato de dados consistente dentro de uma camada ou
componente – Misturar formatos de dados irá tornar a aplicação mais
difícil de implementar, ampliar e manter. Toda vez que você precisar
converter dados de um formato para outro, você é obrigado a implementar o
código de tradução para executar a operação e incorrendo em uma
sobrecarga de processamento.
4. Utilize padrões de projeto de forma a obter um código robusto e obter a reutilização de código
- Mantenha os padrões de projeto consistentes dentro de cada camada –
Dentro de uma camada lógica, sempre que possível, o design de
componentes deve ser consistente para uma determinada operação;
- Não duplique a funcionalidade de um aplicativo – Deve haver apenas
um componente proporcionando uma funcionalidade e esta funcionalidade
específica não deve ser repetida em qualquer outro componente. Isso faz
com que seus componentes coesos e torna mais fácil otimizar os
componentes se uma determinada função ou funcionalidade sofrer
alterações;
- Estabeleça uma convenção de estilo de codificação e nomeação para o
desenvolvimento – Verifique se a organização estabeleceu o estilo de
codificação e padrões de nomenclatura.
5. Adote princípios básicos de projeto de software
- Separação de Responsabilidades – Divida sua aplicação em recursos
distintos com a menor sobreposição de funcionalidade possível. O fator
importante é a minimização dos pontos de interação para alcançar alta
coesão e baixo acoplamento;
- Princípio da responsabilidade individual- Cada componente ou módulo
deve ser responsável por apenas uma característica específica ou
funcionalidade, ou agregação de funcionalidade coesa;
- Princípio da menor conhecimento – (também conhecida como Lei de
Deméter ou LoD). Um componente ou objeto não deve saber sobre detalhes
internos de outros componentes ou objetos;
- Não repita você mesmo (DRY) – Você só precisa especificar a intenção
em um só lugar. Por exemplo, em termos de projeto da aplicação, a
funcionalidade específica deve ser implementada em apenas um componente;
a funcionalidade não deve ser repetida em qualquer outro componente;
- Minimizar projeto inicial – Projete apenas o necessário. Em alguns
casos, você pode requerer um projeto inicial abrangente com realização
de testes para verificar se o custo de desenvolvimento ou uma falha no
projeto será muito alto. Em outros casos, especialmente para
desenvolvimento ágil, você pode evitar antecipadamente um projeto
grande. Se os requisitos da aplicação não são claros, ou se existe a
possibilidade do projeto evoluir ao longo do tempo, evite fazer um
esforço grande prematuramente. Este princípio é conhecido como YAGNI
(“Você não vai precisar dele” – You ain’t gonna need it);
- Considere a operação de sua aplicação – Determine quais métricas e
dados operacionais são exigidos pela infraestrutura de TI para garantir a
implantação e operação eficiente de sua aplicação.
6. Determinar o tipo de aplicação
Escolher o tipo de aplicação adequada é a peça chave do processo de
concepção de uma aplicação. Sua escolha é governado por suas
necessidades e limitações específicas de infraestrutura. Muitas
aplicações devem suportar vários tipos de cliente, e podem fazer uso de
mais do que um dos arquétipos básicos:
- As aplicações concebidas para dispositivos móveis;
- Aplicações rich client projetadas para funcionar primeiramente em um PC cliente;
- Aplicações ricas da Internet projetadas para serem implantadas a
partir da Internet, que suportam interface rica e cenários de mídia;
- Aplicações de serviços projetados para suportar a comunicação entre os componentes fracamente acoplados;
- Aplicativos da Web concebidos para serem executados principalmente no servidor em cenários totalmente conectados.
7. Determinar a estratégia de distribuição
O aplicativo pode ser implantado em uma variedade de ambientes, cada
um com seu próprio conjunto específico de restrições, como a separação
física dos componentes em diferentes servidores, uma limitação em
protocolos de rede, configurações de firewall e roteador e muito mais.
Existem vários padrões comuns de implantação, que descrevem os
benefícios e as considerações para uma série de cenários distribuídos e
não distribuídos. Você deve equilibrar as necessidades da aplicação com
os padrões apropriados que hardware pode suportar, e as restrições que o
ambiente exerce sobre as opções de implantação. Estes fatores irão
influenciar o seu projeto de arquitetura.
8. Determinar os atributos de qualidade desejados
Os atributos de qualidade, tais como segurança, desempenho e
usabilidade podem ser usados para focar o seu pensamento sobre os
problemas críticos que seu projeto deve resolver. Dependendo de suas
necessidades, você pode ter que considerar todos os atributos de
qualidade, ou talvez você só precise considerar um subconjunto. Por
exemplo, cada projeto de software deve considerar sempre a segurança e o
desempenho, mas o projeto talvez não precise considerar os atributos
interoperabilidade e escalabilidade.
9. Determine um processo bem definido de desenvolvimento de software
Um exemplo muito usado a ser considerado é o Processo Unificado da
Rational (RUP) que foi construído envolvendo as seis melhores práticas
para fornecer um processo bem definido e foi baseado nas boas práticas
de desenvolvimento de software.
O RUP é um processo de desenvolvimento de software que assegura a
produção de software de qualidade de forma repetida e previsível, com
isso, se ganha tempo e facilita no desenvolvimento do projeto, visto que
as tarefas são divididas de formas iterativas.

O modelo do RUP é interativo e incremental onde temos que em cada iteração:
- São identificados e especificados os casos de uso mais relevantes;
- E feita a análise e projeto dos casos de uso, usando-se a arquitetura como guia;
- São implementados componentes que realizam o que foi projetado;
- Verifica-se se os componentes satisfazem os casos de uso escolhidos.
Os casos de uso são usados no planejamento e acompanhamento das iterações:

A arquitetura serve para organizar o desenvolvimento, estruturar a
solução e identificar oportunidades de reuso enquanto que os casos de
uso dizem o que deve ser feito.
Dessa forma, podemos resumir o processo de desenvolvimento de software em cinco etapas:

*** Artigo de Macoratti
|
Cada desenvolvedor é diferente, mas o ambiente da sua equipe de
desenvolvimento não tem que ser. Um web app moderno usa muitas
tecnologias diferentes. As dependências comuns para um ambiente de
desenvolvimento web em funcionamento incluem PHP e suas extensões
necessárias, um servidor web, um banco de dados, frameworks de teste, e
outros aplicativos e serviços. A abordagem clássica para auxiliar uma
equipe de desenvolvedores é implementar um servidor e instalar todos os
pacotes necessários para o desenvolvimento. Essa metodologia fornece um
ambiente consistente para todos os desenvolvedores da equipe, garantindo
que todos os colaboradores recebam a mesma experiência em todo o ciclo
de desenvolvimento. No entanto, por mais consistente e homogêneo que um
desenvolvimento remoto possa ser, desenvolver remotamente traz uma série
de problemas, incluindo sacrifícios de velocidade e uma dependência
desagradável de uma conexão confiável à Internet. É igualmente difícil
de mexer com pacotes experimentais quando você sabe que eles poderiam
afetar o ambiente de todos em sua equipe.
Navegar em um sistema de arquivo remoto para encontrar o arquivo que
você deseja editar pode ser complicado. Muitos editores de texto e IDEs
possuem características que tentam minimizar isso, mas eu nunca
encontrei uma que funcionasse de forma confiável e comparável à
velocidade do desenvolvimento local. Salvar um arquivo em uma rede pode
apresentar atraso que se soma a uma quantidade significativa de perda de
produtividade ao longo do tempo. Arquivo de navegação à parte, nada
supera a velocidade de trabalhar localmente. Para trabalhar em sua
máquina local, você tem que instalar todos os pacotes que a equipe está
usando, e cada membro tem de fazer isso também. Essa abordagem apresenta
inconsistência. Como desenvolvedores, nós buscamos consistência,
velocidade, e, mesmo amando a Internet, gostaríamos de ser capazes de
trabalhar sem ela às vezes. Então, o que vamos fazer? Nós construímos
uma máquina dentro de uma máquina que funciona em todas as plataformas e
garante a homogeneidade entre os ambientes de desenvolvimento.
Graças aos avanços na tecnologia de virtualização e da comunidade
open source, existe uma série de ferramentas gratuitas para que qualquer
um possa aproveitar as máquinas virtuais para a sua equipe.
VirtualBox, Vagrant, e Puppet
Para começar, existem alguns aplicativos que são necessários. O VirtualBox é um software de virtualização de hardware que permite que você execute outro sistema operacional em sua máquina local. Já o Vagrant
é um conjunto de scripts que permitem que você manipule facilmente
essas máquinas virtuais a partir da linha de comando. E, por fim, o Puppet permite definir quais alterações de configuração devem ser feitas para que a máquina funcione da maneira que você deseja.
Instale o VirtualBox
Baixe e instale o VirtualBox. Agora você está pronto para instalar qualquer sistema operacional e executá-lo localmente.
Instale oVagrant
O Vagrant é uma ferramenta de linha de comando para construir e
distribuir ambientes de desenvolvimento virtualizados com VirtualBox.
Executando apenas alguns comandos, você pode baixar e provisionar uma
máquina virtual que combina com a de sua equipe.
Ruby e seu gerenciador de pacotes RubyGems são necessários para dar início ao Vagrant. Existem instruções detalhadas para ajudar.
Uma vez que Ruby e RubyGems estiverem instalados, execute o seguinte
comando na sua máquina local para garantir que seus pacotes estejam
atualizados.
gem update --system
Para instalar o Vagrant, execute o seguinte comando em sua máquina local:
gem install vagrant
Configure o Vagrant
Supondo que tudo deu certo, a configuração do Vagrant deve ser fácil. Eu criei uma amostra Vagrantfile
e uma uma configuração base em Puppet, a fim de provisionar uma máquina
com Apache, MySQL, PHP, MySQL, Xdebug, PEAR, CodeSniffer PHP, e
PHPUnit. Você pode clonar meu repositório.
Depois de ter clonado o repositório de exemplo, é
hora de instalar a imagem de base do Vagrant. O seguinte comando fará o
download da box via Internet e armazená-la em cache. É um download 300
MB, mas você só deve ter que fazer isso uma vez.
vagrant box add base http://files.vagrantup.com/lucid32.box
O próximo passo é modificar o seu Vagrantfile. Sua configuração vai
encaminhar as portas de sua máquina local para a máquina virtual. Monte
uma pasta local de sua escolha dentro de sua VM e inicialize o Puppet
como seu provisioner padrão. Eu já fiz isso por você.
Há algumas diretrizes de configuração importantes no Vagrantfile. Vamos dar uma olhada.
# This enables Puppet as the default provisioner
config.vm.provision :puppet
# For verbose output, and you wish to do a dry run, substitute this line
config.vm.provision :puppet, ptions => "--verbose --debug"
Uma vez que o provisionamento estiver completo, você irá acessar o
ambiente LAMP do seu navegador por meio de http://localhost:8080/. A
linha a seguir é a mágica que faz isso:
config.vm.forward_port "http", 80, 8080
Todo este exercício existe para trabalhar com arquivos locais que são
servidos pela VM, e vamos precisar compartilhar um diretório local com a
máquina. A linha a seguir monta a pasta chamada www no seu diretório home para DocumentRoot/var/www) do Apache na máquina virtual.
config.vm.share_folder "www", "/var/www", "~/www"
Se optou por deixar essa configuração como está ou modificá-la, você
pode inicializar a máquina virtual e começar provisionando-a com o
seguinte comando em sua máquina local. Certifique-se de que você está no
diretório que contém o Vagrantfile.
vagrant up
(Se você receber uma stack dump e um erro de permissão, uma explicação está disponível.)
Vagrant inicializa a imagem base com o VirtualBox, e aí executa Puppet com a configuração localizada em manifests/base.pp. Comentei as linhas no arquivo base.pp
para você entender melhor a sua função. Além disso, mantive a
configuração bem simples. A configuração mais avançada vai exigir que
você crie módulos que possam ser herdados, inclusive, parâmetrizados
etc.
Para referência, aqui tem mais documentação sobre as diretivas do Puppet.
Muitos desenvolvedores também escreveram e compartilharam scripts do Puppet com o mundo. Aqui está uma configuração LAMP mais complicada.
Uma vez que a máquina estiver funcionando, se quiser fazer SSH para a máquina, você pode fazer assim:
vagrant ssh
A fim de fazer SSH para a máquina sem o uso de Vagrant (por exemplo,
ao criar um túnel para usar o cliente GUI MySQL), use a maior sintaxe:
ssh vagrant@localhost -p 2222 (password: vagrant)
Existem poucas razões que você configurar a máquina virtual de dentro
dela mesma. Conectar-se à máquina dessa forma deve ser limitada à
execução de ambientes dependentes de ferramentas de linha de comando,
como PHPUnit e MySQL.
Distribuindo e provisionando com Puppet
O Puppet é o verdadeiro herói aqui. Uma vez que uma máquina virtual é
distribuída, ele torna fácil manter a configuração das máquinas
sincronizadas. Pense em sua máquina virtual como descartável. Você deve
ser capaz de destruí-la e recriá-la sem perder funcionalidade. Quaisquer
alterações de configuração devem ser feitas para que a máquina possa
ser propagada para o arquivo de configuração do Puppet e distribuída
através de um repositório Git ou um servidor do Puppet (puppetmaster).
Lembre-se: a chave é que todos tenham o mesmo ambiente e, para fazer
isso, nenhuma modificação personalizada deve ser feita para a máquina
virtual sem compartilhar suas alterações na configuração através do
arquivo Puppet.
Se você tiver modificado base.pp, você pode facilmente reconfigurar a máquina da seguinte forma:
vagrant reload
Você também pode destruir completamente a máquina e começar de novo:
vagrant destroy
vagrant up
Se você quiser apenas suspender a máquina virtual para mais tarde:
vagrant suspend
vagrant resume
Depois de ter configurado uma box, você também pode empacotá-la e
distribuir uma versão binária usando o comando de pacote do Vagrant. Eu
prefiro criar um repositório Git com muitas pastas contendo
configurações diferentes. Por exemplo, você pode ter um ambiente LAMP
estável em uma pasta, e outra contendo um script para instalar o release
candidate do PHP 5.4. No entanto, outra pode conter um ambiente Ruby ou
Python. Alternar entre elas é tão simples como suspender uma máquina e
reinicializar outra.
Desenvolvendo com um ambiente local consistente
Neste ponto, você já deve ser capaz de modificar arquivos facilmente dentro do seu diretório www em sua máquina local, recarregar seu navegador em http://localhost:8080/ e ver os resultados.
Essa configuração serve como um ótimo ambiente de desenvolvimento com
o qual começar. Cada aplicativo terá seu próprio conjunto de
dependências. Você pode até mesmo distribuir a configuração da máquina
virtual dentro do repositório do aplicativo para servir como uma
definição explícita das dependências que ela tem. Com isso, você pode
configurar o servidor de integração contínuo para implementar uma
máquina, provisioná-la, instalar o aplicativo, executar seus testes e
reportar de volta para você.
Existe um último nível de configuração e flexibilidade com uma
configuração como essa. Acima de tudo, porém, sua equipe será capaz de
trabalhar mais rápido e de forma mais eficiente, e você não vai acabar
em uma situação em que algo funciona de forma diferente em um ambiente
em relação a outro. Espero que você encontre uma maneira de usar essas
ferramentas para sua própria saúde mental.
***
Texto original disponível em http://webadvent.org/2011/facilitating-development-environment-consistency-by-jeff-loiselle
|
Depois de ter escrito código para expor APIs através de serviços
web RESTful algumas vezes, eu decidi fazê-lo mais uma vez, só que desta
eu não vou ser pago, nem terei prazos. Vou escrevê-lo e nunca mais terei
que escrever de novo, e vou torná-lo disponível como open source.
O problema é que eu sou uma pessoa muito preguiçosa e não fui capaz
de criar coragem para realmente começar a escrever, o que me leva a este
artigo.
Para que outra pessoa seja capaz de acompanhar o trabalho, obviamente não tenho que explicitar que o objetivo deste exercício é:
- Criar uma ferramenta que pode expor uma API Python de uma forma REST
- A API em si não deve ter que saber sobre a ferramenta
- Deve ser executado em pelo menos em CherryPy e em dois outros frameworks webapp TBD (não, não o Django)
- É preciso lidar com erros HTTP
- Deve ser capaz de codar dados em JSON antes de retorná-los
- Deve ser executada em Python 3.2+
- Não deve se importar com a definição adequada de RESTful
Além disso, algumas coisas boas para se ter:
- Pode fazer ligações entre os recursos de forma mais fácil (se possível)
- Pode ser capaz de usar outros formatos de dados além do JSON
- Pode ser executado em Python 2.7
Por gostar de trabalhar com CherryPy, vou começar a escrever para
CherryPy e depois generalizar a partir de lá. Só para começar, eu criei
um aplicativo mínimo em CherryPy a partir do qual trabalhar, mesmo que
eu vá dividir a ferramenta do framework (ou o framework REST do
framework web?) mais tarde. O código inteiro é assim:
import cherrypy
def requesthandler(*pathargs, **kwargs):
cherrypy.response.status = "500 Server Error"
return "Not implemented"
class PyRest(object):
def index(self, *args, **kwargs):
return requesthandler(*args, **kwargs)
index.exposed = True
CONF = {
'global': {
'server.socket_host': '0.0.0.0',
'server.socket_port': 8888,
}
}
if __name__ == '__main__':
ROOT = PyRest()
cherrypy.quickstart(ROOT, '/', CONF)
def application(environ, start_response):
cherrypy.tree.mount(PyRest(), '/', None)
return cherrypy.tree(environ, start_response)
***
Texto original disponível em http://blaag.haard.se/Simple-REST-ful—ish–exposure-of-Python-APIs/
|
Olá, pessoal. Como DBA há algum tempo, acabo fazendo várias
consultorias em diferentes clientes que têm problemas com seus bancos de
dados. Entre os cenários de bases de dados que eu encontrei,
provavelmente o aspecto que mais afeta o meu trabalho é lidar com
modelos de banco de dados grandes e complexos, que foram criados para
satisfazer os requisitos de armazenamento dos dados.

A origem destes modelos não é incomum nos dias de hoje: com novos
requisitos sendo agregados aos sistemas existentes, os desenvolvedores e
outros profissionais têm que modificar os objetos do banco de dados,
criar novas tabelas, relacionamentos, colunas, tipos de dados e assim
por diante. Além disso, é fato que se a empresa cresce, os dados
armazenados também tendem a crescer muito, o que aumenta a complexidade
para executar tarefas de manutenção no modelo, nos dados, nos objetos, e
no banco de dados em geral. Deste modo, a fim de ser preparado para
lidar com modelos de banco de dados grandes e complexos, apresento
algumas dicas que preparam o terreno e ajudaram a resolver os problemas
do banco de dados do cliente que me contratou para a consultoria.
O objetivo principal deste artigo é apresentar algumas dicas para
ajudar os profissionais que precisam trabalhar com modelos de bancos de
dados complexos, grandes e de difícil compreensão, que qualquer um pode
encontrar no trabalho do dia a dia. Normalmente, esses modelos de banco
de dados armazenam milhares de gigabytes em muitos objetos relacionados,
que podem ser usados por centenas de usuários simultâneos. Então, ter
algum tipo de lista TODO para lidar com este tipo de bases de dados
especiais pode ser boma não apenas para resolver problemas imediatos,
mas também para organizar o trabalho para futuras necessidades e tarefas
de manutenção. Apenas para pontuar, recomendo para aqueles que possuem
pouca experiência com modelagem de banco de dados escutar o episódio do DatabaseCast que fala sobre modelagem de dados.
Sem mais delongas, estas são as minhas dicas para aqueles que têm de
compreender e manipular rapidamente um modelo de banco de dados grande
sem ser seu criador.
1. Identificar as maiores, mais cheias mais usadas tabelas no modelo

Todo modelo de banco de dados grande tem pelo menos uma tabela
principal que contém uma elevada porcentagem do tamanho do banco de
dados. Este é um fato observado através de muitos anos de experiência.
Também é comum encontrar nesta tabela uma grande quantidade de colunas
com tipos de dados diferentes. Na maioria dos casos, essas tabelas
grandes são as mais acessadas e utilizadas pelas aplicações e, por isso,
é muito útil e recomendado conhecer e reconhecer estes objetos
rapidamente, uma vez que você provavelmente vai acabar trabalhando com
eles mais cedo ou mais tarde. Possuir uma maneira de diferenciar essas
tabelas dos outros objetos em um diagrama é um plus que pode economizar
tempo quando for necessária uma olhada rápida no modelo.
2. Use uma ferramenta de controle de versão ou de gestão de configuração
Hoje existem muitas ferramentas que oferecem recursos para acompanhar as
mudanças ao longo do tempo no modelo de banco de dados, como já citado em outro artigo.
Novas colunas, relacionamentos, mudanças de tipos de dados e outras
modificações menores como estas são comuns em modelos de banco de dados
grandes, que tendem a evoluir constantemente para se adaptar a novos
requisitos de negócios e pedidos de mudança na aplicação. O uso de
ferramentas de controle de versão pode requerer a geração de um script
contendo a definição da base de dados dos objetos ou tarefa similar.
Como alternativa, já existem recursos para integrar as ferramentas com
IDEs existentes, tais como o Microsoft Visual Studio.NET com o Team
Foundation Server. Sendo assim, o argumento de que os DBAs não precisam
utilizar alguma ferramenta de controle de versão porque eles não fazem
nenhum programa não é mais aceitável hoje em dia.
3. Saiba como imprimir o modelo de banco de dados completo ou parcial

Ah, o modelo de banco de dados impresso! Milhares de escritórios e
paredes dos departamentos de TI ao redor do mundo são decorados com
essas relíquias que se tornam onipresentes quando o modelo de dados se
torna grande. Como eu aprendi com as muitas equipes que eu trabalhei, há
sempre alguém que pede uma versão impressa de algum objeto ou até mesmo
o modelo de banco de dados inteiro. Portanto, é importante sempre ter
uma maneira simples, rápida e fácil de imprimir uma tabela, ou um
conjunto de tabelas e seus relacionamentos. Opções para gerar arquivos
PDF, imprimir o modelo de banco de dados em páginas separadas (seguido
pela tediosa tarefa de grudar as folhas na ordem) e o uso de cores
diferentes de papel para identificar versões e outros metadados do
modelo estão entre as práticas que vem a calhar para um DBA que trabalha
com uma equipe de desenvolvedores.
4. Identifique os objetos complementares mais utilizados (stored procedures, triggers, funções, índices)

Uma vez que o banco de dados não é composto apenas por tabelas e seus
relacionamentos, é muito pragmático conhecer os outros objetos que
acessam, controlam e manipulam as principais tabelas mencionadas no
primeiro item deste artigo. Eu descobri que os modelos de dados grandes
geralmente empregam muitas stored procedures, views, funções, triggers e
outros objetos que são tão importantes quanto as tabelas que armazenam
os dados. Conhecer a lógica por trás das principais linhas de código que
compõem esses objetos pode economizar tempo durante a depuração,
diminuir o esforço necessário para o processo de tunning e colocar o DBA
em uma posição muito confortável quando há a necessidade de modificar
os dados.
5. Tenha como visualizar o banco de dados em camadas separadas: com e
sem relacionamentos, com e sem índices, com e sem constraints, etc

O mercado é inundado com ferramentas CASE de modelagem que podem
ajudar os profissionais a lidar com grandes modelos de banco de dados
lógicos e físicos. No entanto, se estes modelos puderem ser criados de
forma interativa e incremental da mesma forma como uma imagem é criada a
partir de camadas, o DBA pode ter um meio poderoso para visualizar
detalhes específicos sem toda a complexidade de um modelo grande. Por
exemplo, imagine um modelo de banco de dados de um ERP (Enterprise
Resource Planning) que contém tabelas originais e algumas tabelas
criadas para a integração com um sistema de intranet existente ou mesmo
customizações adicionais ao ERP. Seria muito importante se o DBA pudesse
simplesmente esconder as tabelas do modelo que vieram a partir da
integração com a intranet e, assim, visualizar as informações
necessárias para uma tarefa específica que exige apenas as tabelas de
ERP e vice-versa. Este tipo de disposição em camadas do modelo é uma
maneira muito inteligente para separar e isolar as partes do modelo que
são específicas para uma tarefa, de modo a evitar a propagação da
complexidade do modelo.
6. Use retângulos coloridos para agrupar tabelas de um mesmo subsistema

Outra abordagem que pode ser utilizada para separar e isolar partes
do modelo sem modificá-lo é o uso de desenhos coloridos. Por exemplo,
retângulos coloridos são praticamente um padrão de modelagem utilizado
quando existe a necessidade de separar os subsistemas de um modelo. Esta
técnica é fácil, simples e não apenas agrupa tabelas e relacionamentos,
mas também melhora a legibilidade e a documentação do modelo. É claro,
comentários sobre os elementos do modelo são muito úteis quando eles
descrevem em poucas palavras informações que podem levar horas de estudo
e análise para serem obtidas.
7. Obtenha a ordem correta para inserir, atualizar e remover os
dados em tabelas específicas, respeitando os relacionamentos entre elas

Este item é um pouco complicado, pois geralmente a ordem correta para
inserir, atualizar e remover os dados em tabelas do modelo é programada
na aplicação ou no interior de um objeto no banco de dados como, por
exemplo, uma stored procedure. A parte complicada é que as modificações
são influenciadas e moldadas por regras de negócios e, às vezes, é quase
impossível separá-los. No entanto, se o DBA pode realizar essa
separação e criar um script que inseria, atualize ou remova corretamente
os dados nas tabelas da mesma forma como eles são feitos através da
aplicação, o profissional aumenta seu arsenal de scripts e pode
economizar várias horas durante um chamado ou situação emergencial. Por
favor, não me interpretem mal: eu não estou sugerindo que o DBA ou
qualquer outro profissional deva modificar diretamente os dados da
tabela sem passar pela aplicação (o famoso forçar o dados na mão ou por
debaixo do pano) a fim de resolver rapidamente um problema. O que estou
sugerindo é que o conhecimento de como as tabelas interagem entre si
para uma operação ou tarefa específica pode ser muito útil e deve estar
no conjunto de ferramentas do DBA.
8. Sempre tenha uma forma rápida de procurar pelo nome dos atributos

Modelos complexos podem conter centenas ou mesmo milhares de objetos
de banco de dados. É prudente ter uma maneira simples de pesquisar e
obter informações de metadados a partir dele. Quase sempre é preciso
saber exatamente qual tabela ou view interna do banco de dados contém a
informação quando o DBA está à procura de algo. Boas ferramentas CASE de
modelagem também fornecem opções e recursos adicionais para pesquisas
básicas e avançadas nos elementos de modelagem mesmo se o estágio de
criação do diagrama estiver no início.
9. Tenha um script que gere todos os objetos banco de dados com uma fração de seu dados (10% é ok)

Este ponto é mais uma dica pessoal do que uma ferramenta obrigatória.
Em várias ocasiões eu precisei criar um ambiente novo de banco de dados
para teste/produção/ homologação (ou para qualquer combinação destes) a
partir de um modelo de banco de dados existente. Estas situações exigem
que os todos os objetos devam ser criados em um servidor diferente (às
vezes virtualizado) com toda a complexidade do modelo, porém com apenas
uma fração de seus dados. A marca de mais ou menos 10% parece ser uma
taxa de dados aceitável para começar, porque pode haver ocorrências de
determinadas entidades (produtos, clientes, funcionários, configurações
de aplicativos, etc) no banco de dados necessárias para que a aplicação
funcione. O script necessário para criar todos os objetos é trivial e
pode ser gerado automaticamente por uma ferramenta fornecida pela base
de dados, mas a geração da ordem correta para inserir os dados pode ser
uma tarefa complexa, como discutido no item 7.
10. Mantenha uma lista atualizada das permissões nos objetos mais
comuns para saber rapidamente o que um usuário específico pode e não
pode fazer com os objetos

Talvez a tarefa administrativa mais comum de um DBA envolva o
gerenciamento de permissões. Os comandos DCL (Data Control Language) e
as interfaces gráficas de usuário das ferramentas administrativas de
banco de dados fornecem uma maneira adequada e simplificada para
concessão, revogação e negação das permissões de um objeto para os
usuários. Assim, o DBA que trabalha com um modelo complexo tem que estar
ciente das permissões atribuídas para os objetos e os usuários. A
separação de permissões em grupos pode ser muito útil, mas saber como
indicar rapidamente qual grupo possui um conjunto específico de
permissões para as tabelas de um subsistema do modelo é uma habilidade
imprescindível que qualquer DBA deve possuir. Contar com uma
documentação resumida e agrupada descrevendo as permissões do usuário
para as principais tabelas e objetos pode ter um grande impacto na
realização de tarefas administrativas diárias, especialmente se o banco
de dados trata a segurança de acesso de forma diferenciada.
11. Saiba como prever e estimar o tamanho de objetos específicos para prever o crescimento ou encolhimento do banco de dados

Previsões baseadas em dados reais e modelos estatísticos, criados a
partir de uma distribuição de dados, podem ser muito úteis quando há
necessidade de criar um relatório sugerindo a alocação e/ou realocação
de recursos de banco de dados que afetam os custos de hardware e largura
de banda. Na minha experiência com consultoria achei mais profissionais
atuando por “achismo” do que eu gostaria de admitir quando há
necessidade de justificar alocação/realocação de recursos de banco de
dados. Aqui a dica é simples: sempre monte suas sugestões com base em
estatísticas, métricas, medidas, necessidades e demandas reais para
tornar o seu argumento sólido ao invés de criá-lo na suposição e valores
pobres, previstos sem uma base estatística concreta.
12. Mostre no modelo quais objetos possuem opções de
particionamento, se eles são compactados e a quais os grupos de arquivos
eles pertencem

Os bancos de dados relacionais atuais possuem muitas opções para
particionamento, compressão e de separação interna dos dados armazenados
dentro das tabelas. Ao fazer tarefas de manutençã,o é importante saber
quais tabelas são compactadas, possuem particionamento ativado, como
este particionamento é implementado e onde os dados são armazenados
fisicamente (ou seja, os grupos de arquivos e os arquivos de dados). No
entanto, o modelo de dados e o diagrama de ER não tem uma notação
específica para representar este tipo de informação, pois isso é
responsabilidade do DBA descobrir como descrever e documentar essas
opções e configurações. Comentários, cores diferentes, figuras
geométricas ou até mesmo uma pequena tabela indicando como o
particionamento separa os dados são sugestões que podem tornar o modelo
mais rico e aumentar a percepção da DBA sobre opções e configurações
apenas dando uma rápida olhada no diagrama.
13. Em modelos OLAP centralize a tabela de fatos e tenha à mão uma
maneira de visualizar as hierarquias principais, os níveis, membros e
grãos de cada tabela de dimensão

Modelos de dados OLAP, implementados no estilo estrela, floco de neve
(snowflake) ou uma mistura desses dois estilos, tendem a ser mais
simples que os complexos modelos de dados OLTP. Uma das razões para isso
é porque há mais planejamento envolvido durante a elaboração das
relações e as entidades do que o planejamento de modelos OLTP. Além
disso, as definições das dimensões, níveis, hierarquias e grãos cria uma
estrutura lógica de dados que é facilmente visualizada após uma
inspeção dos detalhes da tabela. No entanto, a documentação pobre das
características de dimensões e as suas relações com os dados da tabela
faz com que o modelo seja mais difícil de compreender. Uma ideia para
simplificar a compreensão de um modelo de dados OLAP é centralizar a
tabela fato no diagrama de tal maneira que ela se destaque das outros e
possa ser claramente identificada à primeira vista. Decorar o modelo com
abundância de informações agrupadas sobre a estrutura e metadados das
dimensões também é uma boa prática que pode economizar tempo quando é
preciso imaginar como os dados vão ser mostrados quando o usuário
estiver navegando em um cubo de dados.
Depois de explicar essas dicas, é fácil perceber a maioria delas se concentra na documentação do modelo de banco de dados e seus objetos.
Obviamente, os principais esforços no desenvolvimento de sistemas estão
relacionados à implementação de novos requisitos e alteração de
recursos existentes. No entanto, a comunidade de TI e especialmente os
DBAs, devem insistir na tarefa de documentação não apenas no código
fonte ou no software a ser entregue, mas também em artefatos que são
importantes para todo o ciclo de desenvolvimento.
Ao seguir as dicas apresentadas neste artigo, os leitores podem se
preparar melhor para lidar, entender e trabalhar com modelos de dados
grandes e complexos. Este cenário não é incomum conforme a aplicação vai
recebendo mais dados. Contar com algumas dicas e melhores práticas
pode ajudar o profissional quando é preciso lidar com dados em um banco
de dados complexo e um modelo extenso. Os leitores que apreciaram as
dicas deste artigo podem encontrar mais conteúdo como este no meu livro
chamado Conversando sobre Banco de dados, já a venda. *** Artigo de Mauro Pichiliani
|
Neste artigo vou trazer o que ganhamos ao escrever User Stories
ao invés de ter que gastar mais tempo escrevendo documentações de
requisitos. Não estou dizendo que não devemos documentar, pelo
contrário. Porém, a ideia é saber o que e como documentar.
O User Stories promove os seguintes pontos:
- Aprendizado;
- Precisão;
- Encoraja a comunicação face-to-face com o cliente;
- Possibilita feedback em tempo real;
- Evita a falsa sensação de que temos tudo documentado de forma correta e só falta implementar;
- Permite uma colaboração e inovação com o time.
Já os documentos de requisitos:
- São grandes e cansativos;
- Encoraja o trabalho por imaginação com falsos ‘achismos’;
- É difícil de planejar;
- Feedback em tempo real é inexistente;
- Desencoraja abertura de colaboração e invocação com o time.
Isso quer dizer que não vou documentar? Não. Em um projeto Agile há
documentação sim, porém ela não é o meio primário de obter as coisas e
nossa última fonte de obter o entendimento, conversar com o cliente, é
mais importante. A diferença é que aqui evitamos o desperdício do tempo
documentando, pois ao terminar toda documentação, o que foi escrito no
início talvez não tenha mais valor para o cliente.
Vou ficando por aqui. Espero que tenham curtido o artigo e possam colocá-lo em prática na realidade de vocês. *** Artigo de Camilo Lopes
|
No meu artigo anterior,
escrevi um pouco sobre o Vagrant dando os passos iniciais para quem não
tinha conhecimento sobre a ferramenta. Neste artigo, pretendo
esclarecer mais alguns assuntos sobre ela e complementar com algumas
informações.
Se você já é mais familiarizado com o universo Linux e servidores,
deve ter sentido a falta de saber como instalar uma máquina do zero ou
como obter outros sabores de Linux. Pois bem, as boxes oficiais do
Vagrant são as versões 32/64 bits dos Ubuntus Lucid e Precise, porém você pode encontrar outras versões feitas por terceiros aqui. Complementando as dicas de link, existem também alguns plugins para o Vagrant.
Alguns devem ter se perguntado no artigo anterior como funciona o vagrant ssh. É simples, talvez tenham reparado esta linha [default] -- 22 => 2222 (adapter 1)
no boot da máquina vitual. O que ela está dizendo é que ocorreu um
mapeamento da porta 2222 do localhost (sua máquina hospedeira) para a
porta 22 da máquina virtual (porta padrão de ssh). Vejam abaixo como
funciona:
host $ ssh vagrant@localhost -p 2222
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
RSA key fingerprint is e6:ad:1e:ee:15:53:7d:a6:ee:7c:aa:04:7a:ad:9a:9a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:2222' (RSA) to the list of known hosts.
vagrant@localhost's password: << senha: vagrant >>
Welcome to Ubuntu 12.04.1 LTS (GNU/Linux 3.2.0-34-generic-pae i686)
* Documentation: https://help.ubuntu.com/
Welcome to your Vagrant-built virtual machine.
Last login: Sun Dec 2 09:19:02 2012 from 10.0.2.2
vagrant@precise32:~$ exit
logout
Connection to localhost closed.
Repare que o Vagrant nos ajuda muito com o simples vagrant ssh,
que nem senha pede. E a importância de entender esse funcionamento é
que provavelmente você não vai usar a máquina apenas para aprender a
usar o shell do Linux. Muito provavelmente o seu interesse vai ser rodar
alguma aplicação Web ou qualquer outra que venha a demandar uma conexão
do o ambiente fora da VM. Então, como fazer isso? Lembram do
Vagrantfile? É nele que vamos fazer a configuração para isso!
config.vm.forward_port 80, 8080
OBS: é preciso fazer o reload da máquina virtual.
A fim de testar o funcionamento, vamos instalar o NGINX apenas para demonstrar o funcionamento.
vm $ sudo apt-get install nginx
vm $ sudo /etc/init.d/nginx start
Feito isso, acesse a url http://localhost:8080 da sua máquina hospedeira e confira se funcionou.
Nesse ponto, acredito que você ainda tenha muitas dúvidas e
questionamentos sobre o Vagrant, e isso é normal, mas com o tempo vamos
aprendendo muito mais. Repare que não usamos muitos comandos até o
momento, e não falei nada sobre as configurações de “hardware” da VM.
Quanto aos comandos, não há muito sobre o que falar, mas a documentação é
muito boa, confira:
host $ vagrant help
Usage: vagrant [-v] [-h] command [<args>]
-v, --version Print the version and exit.
-h, --help Print this help.
Available subcommands:
box
destroy
gem
halt
init
package
provision
reload
resume
ssh
ssh-config
status
suspend
up
For help on any individual command run `vagrant COMMAND -h`
Na parte “hardware”, a máquina que estamos trabalhando no exemplo tem
80 GB de disco e 380 MB de memória por padrão, e isso pode ser
modificado de duas maneiras: 1) alterando no software do VirtualBox
mesmo; ou 2) via Vagrantfile, mas não vou abordar isso neste momento.
Um outro interesse que talvez você tenha é compartilhar dados entre a
máquina hospedeira e a virtual. Isso é simples, a pasta que contém o
Vagrantfile está por padrão compartilhada com a VM, confira:
vagrant@precise32:~$ ls /vagrant/
Vagrantfile
Caso tenha interesse em compartilhar mais pastas ou mudar o local de
compartilhamento, segue o exemplo de configuração para o Vagrantfile:
Vagrant::Config.run do |config|
# ...
config.vm.share_folder "app", "/home/vagrant/app", "/Users/joaovrmaia/app"
end
Explicando:
app é o nome lógico do compartilhamento/home/vagrant/app é o local na máquina virtual onde vai ser montado o compartilhamento/Users/joaovrmaia/app é o local da pasta na máquina hospedeira
Vamos ficar por aqui neste artigo e continuamos a conversa no próximo. *** Artigo de João Victor Rocon
|
Codificar aplicativos e websites exige uma depuração constante de
código para garantir qualidade, desempenho e bom funcionamento. Toda
linguagem, framework e CMS possuem, ou deveriam possuir, seus mecanismos
para essa finalidade. O WordPress e seu ecossistema de plugins nos fornece simples e eficazes formas de depurar códigos.
Depurar código é de extrema importância, mas somente em ambiente de
desenvolvimento, já que no ambiente de produção a regra é o silêncio. O
que eu quero dizer, é que quando você está criando sua aplicação,
codificando seus códigos em sua máquina, você precisa exibir/registrar
os erros que ocorrem para atuar sobre eles. No entanto, quando a
aplicação está em uso, publicada, esses mesmos erros devem ser ocultados
para o usuário final, uma vez que eles expõem informações sobre seu
sistema – como a versão do servidor web, a versão da linguagem, os
caminhos físicos do servidor – e que podem ser usadas por usuários mal
intencionados.
Como ativar e desativar o recurso de debug no WordPress
Por padrão, o recurso de debugging do WordPress vem desativado. Ele é
ativado através de uma constante localizada no arquivo wp-config.php.
Essa constante recebe um valor booleano true ou false para ativar ou
desativar a funcionalidade, respectivamente. Veja os exemplos:
 Função de Debuggind do WordPress desativada
 Função de Debuggind do WordPress ativada
Com a opção de debug ativada, os erros serão exibidos na tela e assim
o desenvolvedor tomará conhecimento da sua existência para atuar em sua
correção e com isso garantir uma melhor entrega. Os tipos de erros
exibidos são:
- Mensagens de erros e alertas do PHP informando sobre erros fatais,
indexes inexistentes verificados pelas funções empty(), isset(), entre
outros;
- Mensagens de debug do WordPress informando sobre o uso de funções e parâmetros em desuso;
- Mensagens de erro de banco de dados do WordPress – a partir da
versão 2.3.2 o WordPress oculta mensagens de erro do banco de dados caso
a constante WP_DEBUG esteja com o valor false.
Particularmente, eu não gosto de exibir os erros na tela, mesmo em
ambiente de desenvolvimento. E tenho alguns bons motivos para isso.
Pense comigo:
- Somos humanos e suscetíveis a erros/esquecimentos. Portanto, pode
acontecer um deploy com a constante WP_DEBUG com o valor true. E como
falei acima, o resultado é uma exposição de dados sensíveis do ambiente;
- Em requisições AJAX não verei os erros, se existirem. Exceto se ficar monitorando através do Firebug, por exemplo;
- Visualmente é feio e impacta na renderização do site no navegador de internet.
Eu disse que não gosto de exibir os erros na tela. Mas gosto muito de
depurar códigos e garantir qualidade. Portanto, eu adiciono outras duas
constantes para trabalhar em conjunto a que conhecemos agora. São as
constantes WP_DEBUG_LOG e WP_DEBUG_DISPLAY. Respectivamente, atribuo o
valor true para uma e false para outra. Com isso, os erros serão
gravados num arquivo de log e não exibidos na tela. Esse arquivo de log
se chama debug.log e fica armanenado em /wp-content.
Se o Apache – ou o servidor web que estiver em uso – não tiver
permissão de escrita, você precisará criar esse arquivo e definir a
permissão apropriada que seria o 666.
Veja um exemplo de código com essas opções ativadas:
 Exemplo de constantes para trabalhar em conjunto com a WP_DEBUG
Espero que com essas sugestões e exemplos você possa monitorar mais
de perto os erros, trabalhar em suas correções e garantir uma melhor
entrega de seus trabalhos. Há outras formas de debuggin no WordPress,
assim como plugins que nos ajudam nesse quesito. Mas por ora conhecemos
um bom caminho.
Grande abraço e até o próximo encontro. *** Artigo de Leandro Vieira
|
Os WebSockets estão começando a se tornar disponíveis a mais
navegadores. Na verdade, hoje, praticamente toda versão mais recente de
cada navegador os suporta, de acordo com o Can I Use.
Mas a melhor parte é que você não precisa sequer de um navegador
moderno com WebSockets disponíveispara, enfim, poder utilizar a
comunicação em tempo real de entre o navegador e o servidor. O Socket.IO
vai mostrar como ele é feito.
Segundo o site Socket.IO:
O Socket.IO pretende tornar possíveis os aplicativos em
tempo real em todos os navegadores e dispositivos móveis, minimizando as
diferenças entre os mecanismos de transporte diferentes. É 100% livre
de cuidados em tempo real em JavaScript.
O Socket.IO oferece uma API de JavaScript simples, baseada em eventos
que te permite comunicar entre o servidor e o cliente sem esforço e em
tempo real. Seu mecanismo padrão é o WebSockets, mas se não for
implementado no navegador do usuário, ele recorrerá à fallbacks, como
Flash e AJAX. Isso o torna disponível para um grande número de
navegadores, como você pode ver aqui.
A biblioteca Socket.IO convencional é escrita em JavaScript tanto
para front end, quanto para back-end, por isso foi projetada para rodar
em um servidor Node.js. É sobre isso que eu vou falar, mas você pode
estar interessado em saber quais outros servidores rodam. Isso você pode
ver na parte inferior da página principal do wiki Socket.IO.
Usando Socket.IO server side
A maneira mais fácil de obter a configuração do Socket.IO para uso no server side é instalá-lo via NPM:
npm install socket.io
Isso foi fácil. Agora temos de começar a usá-lo no nosso código do
aplicativo do servidor. A primeira coisa que precisamos fazer é requerer
a biblioteca e começar a prestar atenção nos eventos vindos do lado do
cliente. Você pode ouvir por um servidor Express, ou apenas dizer-lhe
para usar o seu próprio.
var io = require('socket.io'),
express = require('express');
// Via Express 3.x server
var app = express(),
server = require('http').createServer(app),
io = io.listen(server);
server.listen(80);
// Via Express 2.x server
var app = express.createServer(),
io = io.listen(app);
app.listen(80);
// Standalone
io = io.listen(80);
// Now let's set up and start listening for events
io.sockets.on('connection', function(socket) {
// We're connected to someone now. Let's listen for events from them
socket.on('some event', function(data) {
// We've received some data. Let's just log it
console.log(data);
// Now let's reply
socket.emit('event', {some: "data"});
});
});
Tem muita coisa acontecendo por aqui. Os três primeiros blocos só
mostram uma maneira diferente para podermos configurar um servidor
Socket.IO para ouvir o cliente. Note que 80 é o número da porta que você
está escutando. Você pode muito facilmente ter Socket.IO em uma porta
separada da qual o seu servidor de aplicativo normal está sendo
executado, mas você definitivamente não precisa.
O próximo bloco de código é a parte interessante. Primeiro, nós chamamos io.sockets.on(‘connection’, function(socket) {…}),
o qual apenas espera em volta de um cliente para tentar se conectar a
ele. Depois de receber uma conexão, ele cria um objeto de socket e o
passa para esta função de retorno. Este objeto é usado para se comunicar
diretamente com este único cliente que se conectou. Daqui a pouco vou
te mostrar como transmitir mensagens para cada cliente conectado. Por
enquanto, porém, é preciso aprender a fazer isso com um único cliente.
Dentro deste callback, começamos a criar mais ouvintes com socket.on.
No exemplo acima, estamos ouvindo o cliente para emitir “um
acontecimento”. Quando um cliente emite a mensagem, o callback enviado
para o socket.on será chamado. Observe que a função de retorno de
chamada possui um argumento (de dados) que contém os dados enviados com a
mensagem do cliente. Na nossa função de callback nós apenas o
registramos. Então, emitem uma mensagem de volta para o mesmo cliente
com socket.emit. O primeiro argumento que passamos é o nome da mensagem
ou evento que o cliente deve ouvir, similar à maneira que nós estamos
ouvindo mensagens do cliente. Em seguida, passamos todos os dados que
desejamos enviar junto com a mensagem.

É realmente muito simples. Nós ouvimos mensagens do cliente e
reagimos a elas e enviamos mensagens para ele. Como eu disse
anteriormente, você também pode transmitir mensagens para todos os
clientes conectados e não apenas a um específico. Por exemplo, no caso
de uma sala de bate-papo, cada vez que alguém envia uma mensagem ou se
conecta gostaríamos que todo mundo pudesse vê-la.
io.sockets.on('connection', function(socket) {
// We're connected to someone now. Let's listen for events from them
socket.on('chat message', function(msg) {
io.sockets.emit('message', msg);
});
});
Em vez de chamar emit no socket, chamamos isso de io.sockets, que enviará a mensagem para todos os clientes.
Passando para o cliente
Você viu como era simples usar o Socket.IO no back-end corretamente? É
simplesmente um sistema de mensagens nos dois sentidos baseado em
eventos. A simplicidade da API back-end também se transfere para o front
end. O front end da API é essencialmente o mesmo. Antes de podermos dar
uma olhada na API, porém, temos que adicionar o script para o nosso
aplicativo.
Levei um bom tempo para encontrar o script do lado do cliente. Os
artigos na internet não oferecem muita ajuda. No entanto, eu consegui
descobrir que tem um repositório GitHub separado para o script de cliente Socket.IO.
Você pode encontrar o arquivo que deseja na pasta “dist”. Eu uso ele
desta maneira, porém esta não é a única maneira de servir o JavaScript
do lado do cliente para o navegador. Acontece que o servidor back-end
Socket.IO te servirá o script front end, aí basta apontar para a URL do
servidor de IO e adicionar “/ socket.io / socket.io.js”. Se
você é uma dessas pessoas legais, que estão usando a mesma porta que o
servidor Express, você pode usar uma URL relativa para o script:
<!– Normally –>
<script src="http://<uri:port>/socket.io/socket.io.js"></script>
<!– If same port as Express –>
<script src="/socket.io/socket.io.js"></script>
Agora podemos usar o script! Primeiro, precisamos conectar com o
back-end. É muito simples, basta chamar uma função e dar a ela a URL do
servidor Socket.IO:
var socket = io.connect("http:///");
Agora vamos usar o socket de uma maneira muito semelhante à forma como ele foi usado no back-end:
socket.on("connect", function() {
// Do stuff when we connect to the server
});
socket.on("some event", function(data) {
// Log the data I received
console.log(data);
// Send a message to the server
socket.emit("other event", {some: "data"});
});
Como você pode ver, é diferente quando se tenta obter uma conexão,
mas uma vez que ela é feita, é essencialmente o mesmo código que você
usa no back-end. Eu acho que é semelhante e simples o suficiente, a
ponto de eu não me incomodar em explicá-lo.
Então, isso foi uma introdução decente, mas você provavelmente quer
mais, né? Bem, tem muito mais no que se aprofundar nesse assunto, mas
este artigo já está um pouco longo, então vamos deixar isso para depois.
No próximo artigo vamos discutir namespacing, configuração de
armazenamento e muito mais.
Conclusão
Duas palavras para resumir isso: impressionante e simples. Ele cria
uma super API baseado em eventos simples que nos permite que os nossos
aplicativos se comuniquem prá lá e pra cá entre o front e back ends sem
esforço e em tempo real. Se algo acontecer no servidor, os usuários
podem ser imediatamente inseridos na informação. A coisa mais difícil de
usar o Socket.IO é decidir os nomes para as mensagens.
***
Artigo original disponível em: http://www.joezimjs.com/javascript/plugging-into-socket-io-the-basics/
|
Na segunda parte deste artigo
iniciamos a definição das camadas da nossa solução iniciando com a
camada DTO e a camada de acesso a dados. Continuando a nossa caminhada
cujo objetivo é criar uma aplicação em camadas usando o VB .NET.
Iremos, agora, continuar a definição das camadas da nossa aplicação,
desta vez abordando a camada de negócios – CamadaBLL – que é responsável
pelas regras de negócio do nosso domínio e onde iremos efetuar as
validações. O objetivo da camada de negócios é implementar a lógica da
aplicação, expondo esta lógica para a camada de apresentação e outras
aplicações, e também acessar a camada de acesso a dados.
Passo 6. Definindo as classes do nosso domínio na camada de negócio – CamadaBLL
Como já escrevi, nosso modelo é muito simples e estamos usando o
padrão DAO para implementar as funcionalidades da nossa solução. Nada
muito sofisticado, mas funcional, seguindo o padrão KISS – Keept Simple
Stupid (é um princípio que defende que toda a complicação desnecessária
deve ser evitada. Então se o jeito simples é o “certo”, por que
complicamos? Por pura falta de competência e preguiça. “Simples” não é
sinônimo de fácil).
Seguindo este padrão, vamos criar as classes da camada de negócio –
CamadaBLL -, onde para cada classe do nosso domínio teremos uma classe
de negócio relacionada. Vamos definir as classes e nelas vamos definir
os métodos que acessam a camada de acesso a dados. Eu não estou
realizando nenhuma validação nesta camada para deixar o exemplo mais
limpo e fácil de entender, mas qualquer validação de negócio deverá ser
feita nesta camada.
1. Criando a classe ClasseBLL
Clique com o botão direito do mouse sobre o projeto CamadaBLL e
selecione Add->Class. Depois selecione o template Class e informe o
nome ClasseBLL.vb e clique no botão Add. A seguir, vamos definir o
código abaixo nesta classe:
Imports CamadaDTO
Imports CamadaDAL
Public Class ClasseBLL
Public Function GetTodasClasses() As List(Of Classe)
Dim db As New ClasseDAL
Return db.GetClasses()
End Function
Public Function GetClassePorCodigo(ByVal _CodigoClasse As Integer) As Classe
Dim db As New ClasseDAL
Return db.GetClassePorId(_CodigoClasse)
End Function
Public Function Salvar(ByVal cls As Classe)
Dim db As New ClasseDAL
Return db.Salva(cls)
End Function
Public Function DeletarClasse(ByVal _CodigoClasse As Integer)
Dim db As New ClasseDAL
Return db.DeletaClasse(_CodigoClasse)
End Function
End Class
A classe ClasseBLL possui os métodos:
- GetTodasClasses;
- GetClassePorCodigo;
- Salvar;
- DeletarClasse.
Esta classe está apenas usando os métodos criados para acessar os métodos correspondentes na camada CamadaDAL.
2. Criando a classe AlunosBLL
Clique com o botão direito do mouse sobre o projeto CamadaBLL e
selecione Add->Class. Selecione o template Class e informe o nome
AlunosBLL.vb e clique no botão Add. A seguir, vamos definir o código
abaixo nesta classe:
Imports CamadaDTO
Imports CamadaDAL
Public Class AlunosBLL
Public Function GetTodosAlunos() As List(Of Aluno)
Dim db As New AlunosDAL
Return db.GetAlunos
End Function
Public Function GetAlunosPorCodigo(ByVal _alunoId As Integer) As Aluno
Dim db As New AlunosDAL
Return db.GetAlunoPorId(_alunoId)
End Function
Public Function GetAlunosPorClasse(ByVal _classeId As Integer)
Dim db As New AlunosDAL
Return db.GetAlunosPorClasse(_classeId)
End Function
Public Function SalvaAluno(ByVal _aluno As Aluno)
Dim db As New AlunosDAL
Return db.SalvaAluno(_aluno)
End Function
Public Function DeletaAluno(ByVal _alunoId As Integer)
Dim db As New AlunosDAL
Return db.DeletaAlunoPorId(_alunoId)
End Function
End Class
A classe AlunosBLL possui os métodos:
- GetTodosAlunos;
- GetAlunosPorCodigo;
- GetAlunosPorClasse;
- SalvaAluno;
- DeletaAluno.
Esta classe está apenas usando os métodos criados para acessar os métodos correspondentes na camada CamadaDAL.
As duas classes definidas nesta camada atuam da mesma forma criando
uma instância da camada de acesso a dados e usando o método definido
para realização da operação.
As validações de negócio devem ser realizadas nesta camada. Isso não
está sendo feito neste exemplo pela simplicidade do projeto.
Passo 7. Definindo a camada de apresentação – CamadaWin
Vamos agora definir a camada de apresentação onde criaremos um
projeto Windows Forms para permitir que o usuário gerencie as classes e
os alunos realizando as seguintes operações:
- Cadastrar Classe;
- Alterar Classe;
- Cadastrar Aluno;
Meu objetivo será mostrar que na camada de apresentação deveremos
tratar apenas da apresentação e tratamento das informações, pois a
lógica do negócio e a persistência dos dados estão em camadas separadas.
Dessa forma, a camada de apresentação não deve saber nada sobre a
lógica de negócios nem sobre a persistência de dados.
A camada de apresentação para atualizar as informações irá usar os
serviços da camada de acesso aos dados via camada de negócios,
realizando nesta as validações pertinentes.
No formulário form1.vb que foi criado por padrão vamos definir o leiaute conforme mostra a figura abaixo:
Controles principais do formulário:
GroupBox – grpNovaClasse – Text = Classes
- CboClasses;
- txtNovaClasse;
- btnNovaClasse;
- btnSalvarClasse.
GroupBox – grpAlunos – Text = Alunos
- dgvAlunos;
- txtNovoAluno;
- bntSair;
- btnSalvarAluno.
ErrorProvider – ErrorProvider1
Vamos declarar a utilização dos namespaces:
Imports CamadaDTO
Imports CamadaBLL
Isso é necessário pois precisamos acessar os métodos da camada de negócios e os objetos na camada DTO.
Precisamos definir uma enumeração para declarar qual a ação que
desejamos realizar. A seguir, temos a enumeração FlagAcao que define
três tipos de operação: Insert, Update, Delete e NoAction:
Public Enum FlagAction
Insert = 1
Update = 2
Delete = 3
NoAction = 0
End Enum
No formulário vamos declarar as variáveis para tratar as classes Aluno e Classe:
Private _alunos As List(Of Aluno)
Private _aluno As Aluno
Private _classe As Classe
Private _classes As List(Of Classe)
Esses objetos permitirão acessar e obter informações sobre alunos e classes.
No evento Load do formulário form1.vb vamos carregar a combobox
cboClasses e o DataGridView dgvAlunos com as informações das classes e
alunos:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
carregaCombo()
carregaGrid(cboClasses.SelectedValue)
End Sub
O código do procedimento carregaCombo() é o seguinte:
Sub carregaCombo()
Dim clsBLL As New ClasseBLL
_classes = clsBLL.GetTodasClasses
With cboClasses
.DataSource = _classes
.DisplayMember = "NomeClasse"
.ValueMember = "ClasseId"
End With
End Sub
O código acessa o método GetTodasClasses da camada de negócios e preenche o combobox com as classes.
O código do procedimento carregaGrid() é o seguinte:
Sub carregaGrid(ByVal classeID As Integer)
Dim alnBLL As New AlunosBLL
_alunos = alnBLL.GetAlunosPorClasse(classeID)
With dgvAlunos
.DataSource = _alunos
.ColumnHeadersVisible = True
.ColumnHeadersDefaultCellStyle.ForeColor = Color.BurlyWood
.Columns.Item("ClasseId").Visible = False
.Columns.Item("AlunoId").HeaderText = "Codigo do Aluno"
.Columns.Item("NomeAluno").HeaderText = "Nome do Aluno"
.Columns.Item("Acao").Visible = False
End With
End Sub
O código acessa o método GetAlunosPorClasse() passando o código da
classe e forma a obter e exibir os alunos de acordo com a classe
selecionada.
No evento SelectedIndexChanged da combobox cboClasses temos o código
que obtém as classes e conforme a alteração da classe selecionada
carrega e atualiza o datagridview com os alunos pertencentes à classe
selecionada:
Private Sub cboClasses_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboClasses.SelectedIndexChanged
If cboClasses.SelectedIndex = -1 Then Exit Sub
Dim cls As Classe
Dim clsBLL As New ClasseBLL
cls = clsBLL.GetClassePorCodigo(cboClasses.SelectedIndex + 1)
If Not IsNothing(cls) Then
carregaGrid(cls.ClasseId)
Me.txtNovaClasse.Text = cls.NomeClasse
End If
End Sub
No evento Click, do botão nova classe, apenas preparamos a interface para incluir uma nova classe ou cancelar a operação:
Private Sub btnNovaClasse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNovaClasse.Click
If btnNovaClasse.Text = "Nova Classe" Then
btnNovaClasse.Text = "Cancelar"
btnSalvarClasse.Enabled = True
Me.txtNovaClasse.Text = ""
Me.cboClasses.SelectedIndex = -1
grpNovaClasse.Text = "Informe uma nova Classe"
grpNovaClasse.BackColor = Color.MintCream
grpAlunos.Visible = True
grpAlunos.Enabled = False
Me.txtNovaClasse.Focus()
ElseIf btnNovaClasse.Text = "Cancelar" Then
grpNovaClasse.BackColor = Color.Pink
grpAlunos.Visible = True
grpAlunos.Enabled = True
btnNovaClasse.Text = "Nova Classe"
End If
End Sub
No evento Click do botão Salvar chamamos o procedimento SalvarClasse():
Private Sub btnSalvarClasse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvarClasse.Click
SalvarClasse()
End Sub
O procedimento SalvarClasse() realizar a inclusão de uma nova classe ou atualização de uma classe existente:
Sub SalvarClasse()
Dim bln As Boolean
Dim clsBLL As New ClasseBLL
Dim cls As New Classe
If txtNovaClasse.Text = String.Empty Or txtNovaClasse.Text.Length < 5 Then
MsgBox("Informe o nome da nova classe (minímo 5 caracteres).")
txtNovaClasse.Focus()
Return
End If
cls.NomeClasse = Me.txtNovaClasse.Text.Trim
If cboClasses.SelectedIndex = -1 Then
cls.Acao = FlagAcao.Insert
Else
cls.ClasseId = cboClasses.SelectedValue
cls.Acao = FlagAcao.Update
End If
bln = clsBLL.Salvar(cls)
If bln Then
MessageBox.Show("Dados Atualizados com sucesso !")
If cboClasses.SelectedIndex = -1 Then
carregaCombo()
cboClasses.SelectedIndex = 0
End If
Refresh(cboClasses.SelectedIndex)
grpNovaClasse.Visible = True
grpAlunos.Enabled = True
btnSalvarClasse.Enabled = False
Else
MessageBox.Show("Ocorreu um erro ao atualizar os dados !!")
btnSalvarClasse.Enabled = False
End If
End Sub
No código do evento Click do botão Salvar (grpAlunos) verificamos se
existe uma classe selecionada e um nome de aluno informado para chamar o
procedimento SalvarAluno():
Private Sub btnSalvarAluno_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvarAluno.Click
ErrorProvider1.Clear()
If cboClasses.SelectedIndex = -1 Then
ErrorProvider1.SetError(Me.cboClasses, "Selecione uma Classe!!")
Exit Sub
End If
If Me.txtNovoAluno.Text.Trim() = "" Then
ErrorProvider1.SetError(Me.txtNovoAluno, "Informe o nome do Aluno !!")
Exit Sub
End If
SalvarAluno()
End Sub
O procedimento SalvarAluno() obtém a classe e o nome do aluno, define
a ação e chama o método SalvaAluno() passando o objeto Aluno para
persistência dos dados:
Sub SalvarAluno()
Dim alnBLL As New AlunosBLL
Dim aln As New Aluno
Dim cls As New Classe
Dim clsBLL As New ClasseBLL
Try
'obtem a classe selecionada
cls = clsBLL.GetClassePorCodigo(cboClasses.SelectedIndex + 1)
'obtem o id da classe
aln.ClasseId = cls.ClasseId
'obtem o nome do aluno
aln.NomeAluno = Me.txtNovoAluno.Text
'define a ação
aln.Acao = FlagAcao.Insert
'usa o método para salvar o aluno
alnBLL.SalvaAluno(aln)
MessageBox.Show("Dados do aluno atualizado com sucesso !!")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Estamos sobrescrevendo o método Refresh do formulário onde atualizamos o controle combobox cboClasses conforme abaixo:
Public Overloads Sub Refresh(ByVal intID As Integer)
cboClasses.DataSource = _classes
cboClasses.Refresh()
cboClasses.SelectedIndex = intID
End Sub
Finalmente o evento CLick do botão Sair encerra a aplicação:
Private Sub btnSair_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSair.Click
Application.Exit()
End Sub
Como podemos observar, nossa camada de apresentação não utiliza
nenhuma referência para realizar a persistência. Ao invés disso ela usa
os métodos da camada de negócios para realizar tais operações. Assim,
qualquer mudança na camada de acesso a dados não afeta diretamente nossa
camada de apresentação.
O exemplo da camada de apresentação não está completo e foi usado
apenas para ilustrar a separação das responsabilidades em camadas.
Assim, completamos a nossa caminhada em sete passos onde percorremos as
etapas básicas e em cada passo abordamos os conceitos relacionados à
separação de responsabilidades e a criação de camadas.
Pegue o projeto completo aqui: AppTresCamadas.zip
Agora para concluir, vou fazer uma pergunta: você acha que nossa
aplicação pode ser considerada uma aplicação orientada a objetos? Não.
Ele usa uma abordagem procedural que mescla a utilização dos recursos da
orientação a objetos disponíveis na linguagem VB .NET. Em uma aplicação
totalmente orientada a objetos a abordagem seria diferente… *** Artigo de José Macoratti
|
E acredito que sempre será assim. Algum tempo atrás, grandes
projetos de software de sucesso foram desenvolvidos em metodologias das
quais programadores mais novos nunca ouviram falar, mas que deram bons
resultados na sua época (e algumas continuam dando). Esse programador
mais novo provavelmente nunca trabalhou usando uma metodologia
tradicional como Cascata e o RUP, por exemplo. Ele já entrou no
fantástico mundo da agilidade usando XP, Scrum, Kanban…
Cada equipe de desenvolvimento, de acordo com o tipo de projeto a ser
atacado, opta pela metodologia que considera a melhor para alcançar
seus resultados. Algumas até criam suas próprias metodologias ou
variações das já existentes. Variações!? Sim, variações. Eu já ouvi
falar em ScrumBut, ScrumBan, Scrum++, xUP, e por aí vai.

Existem equipes que optam por mesclar metodologias coletando o melhor
de cada uma delas, adaptando-as às suas realidades, mas sem criar
rótulos.
Seja trabalhando no modelo tradicional ou no ágil, o que todos
queremos é produzir com qualidade, e a opção de escolha de cada
metodologia deve ser respeitada, pois cada um sabe onde seu calo aperta.
Inúmeros são os profissionais que não abrem mão de uma farta
documentação, de um completo levantamento de requisitos, de uma
modelagem abrangente, mesmo desenvolvendo em um cenário de agilidade. E,
falando no tradicional, quem disse que não podemos utilizar técnicas
ágeis no RUP, por exemplo?
Planejar os testes, documentar, levantar requisitos, prototipar,
modelar, programar em pares… Nada disso é propriedade de um nome, de uma
sigla.
Às vezes estamos tão ligados no by the book que deixamos de aplicar várias coisas bacanas que dão resultado para não “ferir” os princípios da metodologia que escolhemos.
Hoje estamos no fantástico mundo da agilidade, que tem seu valor
reconhecido, mas ainda existem muitas equipes que não a aplicam e
continuam desenvolvendo produtos de qualidade.
A transição de uma metodologia para outra é sempre crítica. O
profissional está saindo de uma zona de conforto, na qual tem suas
entregas garantidas, para uma nova filosofia de trabalho. Isso é
difícil, mas não impossível. Ousar mudar é para poucos.
Existem muitas discussões nos fóruns sobre soluções mirabolantes,
sobre modelos de resolução de problemas, padrões que não podem deixar de
ser seguidos.
As metodologias de hoje serão substituídas algum dia. Ou alguém
duvida disso? Os nomes e as siglas vão mudar. Aí nós vamos falar que
estávamos trabalhando de maneira errada? Claro que não! Tudo aquilo que
aplicamos com sucesso hoje, vamos ter muita dificuldade de abrir mão.
Podemos mudar? Sim, mas o valor do novo tem que ser provado. E será
provado. Coisas novas e boas vão surgir. Que venham as novas
metodologias, mas as boas práticas vão ficar.
Até a próxima. *** Artigo de Max dos Santos
|
Quando eu explico para as pessoas que um bom Wireframe é mais que
o suficiente para o desenvolvedor front-end, vulgo HTMLer ou
implementador começar a codificar, muitos webdesigners até entendem o
fluxo, mas simplesmente NUNCA o praticam. Depois de algumas observações,
percebi os motivos óbvios:
Pessoas metódicas
Eu sou uma pessoa metódica e sei como isso é. Pessoas metódicas
(dependendo do grau) até conseguem sair da caixa, mas não gostam, nem se
sentem a vontade; por isso, preferem esperar o design completo para
então começar o seu trabalho.
Desorganização
Pessoas desorganizadas com o seu CSS não conseguem pensar em como
estruturá-lo, de forma que depois tenham que mexer novamente e adaptarem
a qualquer mudança. Assim sendo, precisam do layout finalizado para
minimizar a chance de refazer a implementação de algo.
Preguiça
O pior aliado de um desenvolvedor qualquer profissão
é a preguiça. A ideia de deixar tudo até os 47 do segundo tempo é um
câncer que cada vez mais corrói sua produtividade e qualidade
profissional e pessoal. Muitas vezes, o desenvolvedor acredita
veementemente que é melhor ganhar uns dias, enquanto o designer prepara o
layout, para só depois começar a trabalhar. Com um pouco mais de visão,
o mesmo aprontaria o que desse antes para enquanto o designer estivesse
preparando o layout final, ele poderia pensar em formas de melhorar o
código, experimentar algo novo, propor uma funcionalidade diferente para
a equipe e etc.
Surpresa!
O mais interessante disso tudo é que esse não é o principal motivo
para o não desenvolvimento estrutural do HTML e CSS. O principal motivo é
que quase em sua totalidade, o design da interface só é pensado ou
levado a sério no momento que o designer faz o layout final. Muito se
fala sobre wireframes, softwares, artigos, blogs, livros sobre AI, mas
na prática, o mercado em sua maioria (me refiro mais à agências web)
ainda continua com o seu fluxo medroso e antigo.

Modelo tradicional
O modelo é bem simples: cada etapa finalizada dá origem ao começo da
etapa seguinte. Processo demorado e um profissional depende do término
do outro.
Modelo avançado
O modelo necessita de uma documentação bastante definida no protótipo
para que a etapa de codificação possa ser iniciada. Mais de um
profissional pode atuar ao mesmo tempo no projeto. Com a interação e
arquitetura definida, ainda pode ser iniciada uma terceira etapa
simultânea que é a do desenvolvimento do sistema, ou programação.
Funcionamento em SCRUM
Muitas empresas aqui no Brasil e no exterior já trabalham com
metodologias ágeis; a mais famosa atualmente é o SCRUM. O projeto é
dividido em sprints, assim sendo, temos que aproveitar a sprint 1 para
prever, mapear e arquitetar o que será feito na sprint 2. Paralelo a
isso, temos que codificar o que será trabalhado na sprint atual e
corrigir erros e melhorias da sprint atual e sprint anterior. Com um
número de designers para atender esse fluxo, ele seria excelente, porém
não é a realidade da maioria das empresas de desenvolvimento web, muitas
vezes prejudicando o trabalho do design ou sobrecarregando o mesmo.
Crítica pessoal: Pelos livros que eu li, cursos e
treinamentos em Scrum que participei pela Petrobras, além da prática,
tenho certeza que quem inventou Scrum e divulgou para empresas de
desenvolvimento, em nenhum momento parou para estudar o processo de
esign de interfaces e sua importância para o produto e empresa.
O outro lado da moeda, o design centrado no desenvolvedor
Quando buscamos informações sobre design, achamos muitas informações
sobre design centrado no usuário, caso você não esteja ainda totalmente
confiante que faça isso, leia esses artigos de grandes nomes da web:
O problema disso tudo é a grande difusão desse conceito em que o
designer se concentra apenas no usuário e esquece que alguém terá que
transformar isso em algo usável. De que adianta fazer um produto
magnífico para o usuário se ele fará a empresa comprar uma máquina do
Japão por 2 milhões, que não cabe na área da fábrica atual e precisará
treinar seus mais de 800 empregados? O designer tem que levar isso em
conta, mas quando o produto é online, poucos se concentram nisso.
Uma dica para ajudar o front-end na parte técnica é preparar o PSD de forma profissional, seguindo algumas regras como:
- Dar nomes intuitivos as layers;
- Organizar conceitualmente as layers em pastas;
- Colorir conceitualmente pastas também é interessante;
- Dê flattern nas layers que foram utilizados efeitos em mascaras, isso facilita e muito na hora do desenvolvedor cortar
- Todo ícone utilizado deve ser guardado numa pasta e ser enviado no
mesmo zip que o PSD, assim o desenvolvedor não precisa pegar ícone por
ícone e ir cortando;
- Padronize o espaçamento, isso não só é bom para o conforto da tela e
aproximação de objetos baseados em Gestalt, como também facilita a
medição para o CSS;
- Se utilizar fontes que não são do sistema, enviá-las junto com o zip;
- Crie uma pasta ou um outro PSD com o hover (interações), isso ajuda
muito na hora do usuário criar o CSS e até mesmo influencia no HTML
(dependendo do caso);
- Caso tenha um background grande bem trabalhado ou que se repita, envie junto com o zip;
- Crie um pdf ou qualquer outro tipo de documento, informando as cores
usadas (hexadecimal), fontes usadas nos elementos h1, h2, h3, hn, p,
li, etc., espaçamentos padronizados, largura de colunas.
Existem outras dicas na apresentação que fiz junto com o Victor Montalvão, no 15 EDTED, com o título Oficina de Planejamento de corte, o seu layout virando código.
Na prática
Entendemos que a baixa fidelidade é a melhor forma de começar o seu
wireframe, pois é nela que você trabalhará e contraporá suas ideias.
Porém acredito que após isso, ainda antes do layout, você pode tratar
esse wireframe detalhado, e esse sim apresentar para a equipe e para o
seu cliente. Um wireframe de alta fidelidade ou até mesmo um Interface
Design antes do Context Design permitem o trabalho simultâneo de
desenvolvimento front-end e back-end. Um exemplo disso:
Com
uma interface definida, você consegue captar a semântica de cada item,
além de estruturar da melhor forma o seu HTML para que seja flexível e
limpo ao mesmo tempo, com classes genéricas e reaproveitáveis. O
programador, por sua vez, já saberá os campos que serão utilizados e
preenchidos pelo cliente. Tudo bem mais ágil e econômico não?
Seu
HTML fica facilmente definido, inclusive o CSS estrutural pode ser
feito, deixando os estilos de cores e fontes para uma segunda etapa.
Conclusão
É evidente que não é da noite pro dia que uma equipe chega a essa
maturidade, mas é algo a ser sempre perseguido, inclusive inovado. Se
criar algo novo na sua equipe ou empresa, me conte por aqui ou por
e-mail ok? *** Artigo de Bernad de Luna
|
Um dos fundamentos de maior relevância do JSF é seu ciclo de vida
que se dá entre a requisição e a resposta do servidor de aplicação. São
vários os motivos da existência deste ciclo, dentre estes, temos:
- Manter o controle de estado dos componentes de interface;
- Alinhar ouvintes de eventos com seus respectivos eventos;
- Controle de navegação entre páginas, que deve ser realizado pelo servidor;
- Permitir que validações e conversões sejam realizadas no lado do servidor.
Indo direto ao assunto, o ciclo de vida do JSF se divide em seis fases (veja a figura abaixo), que são:
- Fase 1: Restore View (Restauração da visão);
- Fase 2: Apply Request Values (Aplicar valores da requisição);
- Fase 3: Process Validation (Processar as validações);
- Fase 4: Update Model Values (Atualizar valores de modelo);
- Fase 5: Invoke Application (Invocar aplicação);
- Fase 6: Render Response (Renderizar a resposta).

Vejamos agora o que acontece em cada uma.
Fase 1: Restore View (Restauração da visão)
A partir de uma requisição proveniente do servlet FacesServlet, é
identificado qual visão está sendo requisitada por meio do ID desta que é
determinado pelo nome da página JSP. Tendo identificado a página, esta é
salva no FacesContext (caso ainda não tenha sido salva) e sua
respectiva árvore de componentes é construída.
Fase 2: Apply Request Values (Aplicar valores da requisição)
Nesta fase, cada componente da visão, criado ou recuperado, passa a
ter o seu valor. Nesse contexto, existem algumas diferenças ocasionadas
pelo valor do atributo “immediate” em cada componente:
- immediate = false: Neste caso, que é o padrão, os valores são
apenas convertidos para o tipo apropriado. Se o valor é um Integer, é
convertido para Integer.
- immediate = true: Os valores são convertidos e validos.
Fase 3: Process Validation (Processar as validações)
Esta é a primeira manipulação de eventos do ciclo, aqui serão
executadas as validações definidas pelo servidor em cada componente. Não
existindo valores inválidos, o ciclo segue para a Fase 4. Existindo,
uma mensagem de erro será gerada (adicionada ao contexto do Faces,
FacesContext) e o componente é marcado como inválido. Neste caso, o
ciclo segue para a Fase 6 (Renderizar a resposta).
Fase 4: Update Model Values (Atualizar valores de modelo)
Os valores enviados pela requisição e validados pela fase 3, são
atualizados em seus respectivos atributos contidos nos backings beans,
onde somente as propriedades enviadas são atualizadas. É importante
dizer que, mesmo após a fase de validação, fase 3, os valores enviados
podem estar inválidos a nível de negócio ou a nível de conversão de
tipos, o que pode ser verificado pelo próprio bean.
Fase 5: Invoke Application (Invocar aplicação)
Nesta fase, os valores dos componentes da requisição, estão validados
convertidos e disponíveis nos backings beans. Assim a aplicação tem os
insumos necessários para aplicar a lógica de negócio.
Outro fator importante dessa fase, é o direcionamento do usuário de
acordo com as submissões realizadas pelo mesmo. Por exemplo, se ouve
sucesso no processamento dos dados enviados, o usuário é redirecionado
para uma determinada página, se não, permanece na mesma página.
Fase 6: Render Response (Renderizar a resposta)
O processo ‘Renderizar a resposta’ consiste na apresentação da página
referente ao resultado da aplicação ao usuário. Neste contexto existem
três possibilidades:
- Caso seja a primeira requisição da página: Os componentes associados são criados e associados a visão;
- Caso seja a primeira submissão: Os componentes são traduzidos para o HTML;
- Caso tenha ocorrido algum erro: Existindo os marcadores
<f:message /> ou <f:messages /> na página, os erros são
exibidos ao usuário.
Visão geral
No desenvolvimento em JSF existem dois perfis diferentes de
desenvolvedores: os que desenvolveram aplicações JSF e os que
desenvolveram componentes. No primeiro perfil, as fases de maior foco
são a 2, 3, 4 e 5. Já no segundo, são a 1 e 6, que estão mais
relacionadas a árvore de componentes no lado do servidor e de
componentes da visão. Sendo assim podemos agrupar as fases da seguinte
forma:
- Fases focadas no desenvolvimento de aplicações JSF
- Fase 2: Apply Request Values (Aplicar valores da Requisição)
- Fase 3: Process Validation (Processar as Validações)
- Fase 4: Update Model Values (Atualizar Valores de Modelo)
- Fase 5: Invoke Application (Invocar Aplicação)
- Fases focadas no desenvolvimento de componentes de visão
- Fase 1: Restore View (Restauração da Visão)
- Fase 6: Render Response (Renderizar a Resposta)
*** Artigo de Samuel Vinícius
|
Todo mundo fala sobre testes automatizados para o seu código, mas
isso é apenas a metade dos testes que eu preciso. E o front-end?
Formulários também precisam ser testados, e o SimpleTest é maneira como consigo isso.
O SimpleTest é muito fácil de instalar. Basta baixar a versão mais recente, fazer o upload para o servidor e, em seguida, descompactá-lo. É isso! Agora você pode começar a escrever testes.
O SimpleTest pode lidar com todos os testes unitários para o seu
código nos bastidores, mas também possui um navegador interno, para que
ele possa testar o front end também. Para começar, crie um arquivo PHP
para seus testes. Inclua autorun.php do SimpleTest. Para os testes que utilizam o navegador interno, você também vai precisar incluir web_tester.php. Em seguida, crie uma classe para os testes que estenda a classe WebTestCase.
require_once 'simpleTestDir/autorun.php';
require_once 'simpleTestDir/web_tester.php';
class contactForm extends WebTestCase {
}
Agora é a hora de começar os testes reais. O SimpleTest oferece uma
série de opções para testar. Você pode verificar o título da página, se o
texto específico está presente em uma determinada página, se um
determinado cookie existe, e muito mais. Consulte a documentação do SimpleTest para uma lista completa de opções.
Uma das coisas que eu gosto ao realizar testes é me certificar de que
uma mensagem de erro específica é exibida quando dados ruins são
enviados em um formulário. Com o SimpleTest, isso é fácil. Carregue um
formulário usando $this->get() e forneça a URL da página que você deseja testar. Insira os dados em um campo usando $this->setField()
e forneça o nome do campo como o primeiro argumento e o valor do campo
como o segundo argumento. Faça um commit de um erro, como deixar um dos
campos obrigatórios vazios; em seguida, envie o formulário com $this->clickSubmit()
e forneça o título do botão enviar. Finalmente, você pode verificar se a
mensagem de erro está sendo exibida na página executando $this->assertText() e fornecendo o texto da mensagem de erro. O código seria algo assim:
require_once 'simpleTestDir/autorun.php';
require_once 'simpleTestDir/web_tester.php';
class contactForm extends WebTestCase {
function testUsernameField() {
$this->assertTrue($this->get('http://myWebsite.com/myForm/'));
$this->setField('username', 'bad username');
$this->clickSubmit('Send');
$this->assertText('Please enter a username with no spaces.');
}
}
Agora, quando você visualizar seu arquivo de teste em um navegador,
você receberá um relatório dizendo que o caso de teste está completo e
que – espero – você tem duas passagens, uma para o seu assertTrue e um para seu assertText.
Você conseguiu; você está testando seu formulário! O SimpleTest também
se integra a muitas das plataformas de integração contínua, de modo que
você pode incorporar testes front-end ao resto de sua caixa de
ferramentas de testes.
***
Texto original disponível em http://phpadvent.org/2011/dont-forget-the-front-by-beth-tucker-long
|
Estamos vivenciando o início de uma profunda transformação no
modelo computacional e no papel de TI, mas isto muitas vezes não fica
claro para nós. A razão é simples: estamos em um período que podemos
chamar da transição do momento pré-cloud para o pós-cloud. Mas se
observarmos os sinais de mudanças, vemos que agora é um momento em que
começamos a ver o modelo de cloud computing se disseminando e a área de
TI começando a assumir novos papéis dentro da organização.
Toda mudança causa estranheza no início, principalmente quando o
paradigma é quebrado. Compara-se as mudanças com os modelos que estamos
acostumados e muitas vezes não percebemos que no período de transição,
como vivenciamos hoje, o paradigma ainda não está completamente
definido. A transição, como o nome diz, é transitória, ou seja, não é o
modelo que vai perdurar no futuro. É passageira.
Para ficar mais claro as diferenças entre os modelos pré e pós-cloud,
vamos analisar o momento atual. Este momento vamos denominar como
periodo pré-cloud e é basicamente fundamentado na arquitetura
cliente-servidor, com uso muito limitado (quase embrionário) de cloud
computing. É um momento de evangelização do mercado. Na maioria das
empresas, a área de TI é responsavel pelos custos e controle dos
recursos computacionais. É um centro de custos. Sua função primordial é
suportar as operações do negócio, padronizando as tecnologias e
determinando quais que podem ou não entrar nas empresas. É um modelo que
tanto os fornecedores, quanto os compradores de tecnologia se
acostumaram e baseados nele criaram todo um ecossistema. As empresas
planejam desenvolver ou contratar novas aplicações, adquirem tecnologia
(hardware e software) e aguardam um determinado período de tempo (às
vezes semanas e meses) até que as máquinas físicas sejam instaladas e o
software disponilizado para uso.
O período de transição já nos mostra algumas mudanças. Começamos a
ver o cloud computing cada vez mais disseminado, mas devido aos
questionamentos e interesses dos dois lados (vendedores e compradores),
busca-se um modelo que não faça transformações radicais. Notamos
claramente a adoção do que chamamos de nuvens híbridas, com parte da
demanda computacional das empresas sendo atendidas pelo modelo de nuvem
(de IaaS a SaaS) e parte ainda no modelo on-premise. Ou seja, vemos
algumas soluções indo para a computação em nuvem ao mesmo tempo que
vemos em paralelo novas aquisições de hardware e licenças de software.
Mas a área de TI começa a se desgarrar do paradigma de controlar os
recursos computacionais, passando muitos deles para provedores de nuvem
externos. A consumerização de TI é um impulsionador para acelerar o
deslocamento do eixo da adoção de tecnologias na empresa da TI para os
usuários. Começamos a ver TI focar-se mais na padronização dos serviços
do que nas tecnologias. Ou seja, em vez da preocupação em definir
padrões de tecnologia, a TI começa a buscar padrões de serviços em
nuvem. É um periodo desafiador, pois os principais provedores de nuvem
tentam impor seus próprios padrões como padrões de fato do mercado. A TI
deve buscar concentrar esforços em adotar provedores que se baseiem em
padrões abertos, pois o momento atual é de transição e a visão
estratégica terá que olhar o longo prazo.
Provavelmente, no fim desta década ou início da próxima estaremos
vivenciando o período pós-cloud ou seja, o momento em que não terá mais
sentido falar em cloud computing e sim apenas em computing, pois este
será o paradigma computacional dominante. Claro que quando falamos em
modelo dominante não estamos falando que 100% do cenário computacional
estará em cloud. Sempre haverá demandas e especificidades que exijam a
preservação do modelo atual em determinadas situações.
Mas quando estivermos neste modelo, qual será o papel da TI? A
maioria dos serviços estará em nuvens públicas e em empresas de maior
porte, com uma parte também em nuvens privadas. Uma diferença é que o
aparato tecnológico, como servidores e middleware serão commodities. A
TI vai criar diferença se deixar de ser suporte do negócio para ser
parte integrante. É o momento em que falar da sigla CIO como Chief
Information Officer será tão revelador da obsolescência quanto o título
de gerente de CPD. Deveremos falar em funções como Chief Innovation
Officer ou Chief Digital Officer.
O período pós-cloud é o modelo “TI is the Business”, ou seja, não
terá mais significado debater se TI está ou não alinhado com o negócio.
TI será o negócio. As discussões e decisões corporativas vão incluir
tecnologias desde o inicio, pois esta estará cada vez mais invisível e
ubiqua. A Tecnologia estará tão integrada às discussões como o dinheiro
para investimento. Praticamente todo e qualquer produto ou serviço, seja
aos clientes ou de uso interno, terá TI embutida. Lembramos que não
estamos falando apenas da TI como a vemos hoje, responsavel basicamente
pelos ERPs e bancos de dados, mas a nova TI deverá incluir toda
tecnologia embutida na organização, inclusive a operacional, que está
embutida em objetos, câmeras, sensores, etc.
A TI passará a ser vista como geradora de receita e não como centro
de custo. Para isso acontecer, alguns níveis de amadurecimento deverão
ocorrer. Primeiro é indicutível que esta nova TI tenha a excelência
operacional como padrão mínimo. E para conseguir isso, a computação em
nuvem é fundamental. O processo de automatização que a computação em
nuvem embute é essencial para alcançar esta excelência operacional. Não
terá sentido nenhum a área de TI gastar horas ou dias de recursos
humanos para fazer upgrades de software ou exercer tarefas que não
agregam valor para o negócio. Muito menos fazer as áreas de negócio
esperarem semanas por um novo recurso computacional como um servidor…
Outro nível de amadurecimento será a mudança no perfil profissional
dos gestores e profissionais de TI. Quanto maior o uso de provedores de
nuvem, menor a necessidade de administradores de sistema in-house. Estes
estarão concentrados nos provedores. Quanto maior a utilização de PaaS,
menor a demanda por desenvolvedores dentro de casa, pois grande parte
desta tarefa poderá ser feita externamente. Mas conhecer em profundidade
o negócio e alavancar novos produtos e serviços com tecnologias e
processos inovadores fará toda a diferença. Esta deverá ser a postura e o
perfil do profissional de TI: conhecer e aplicar de forma pró-ativa e
inovadora as tecnologias que farão diferença para o negócio.
A linguagem de TI também deverá mudar. Reduzir custos e gerenciar
ativos de TI passam a ser função de provedores. Não será uma tarefa
nobre para o novo perfil da TI. Mas entender do negócio e discutir como
reduzir fraudes em sistemas de seguro e bancários, diminuir o churn rate
de uma empresa de telecomunicações, reduzir as ocorrências de
“out-of-stock” do varejo e assim por diante, é que deverão ser as
conversas de corredor da TI e não se o sistema operacional é Linux ou
outro qualquer.
Este não é um processo que vai acontecer de uma dia para outro.
Passaremos, aliás, estamos passando por um período de transição e as
empresas e os CIOs deverão ter uma estratégia para transformar suas TI’s
em um centro de resultados. Ficar parado esperando a mudnça é que não
tem sentido. Elas acontecerão, queiramos ou não. *** Artigo de Cezar Taurion
|
Prosseguindo nos objetivos da Certificação LPI, hoje vamos para a
segunda parte dessa série de artigos. Para poder ver como começamos
esse assunto, só clicar aqui. Vamos lá?!
uniq
Esse comando mostra o conteúdo, suprimindo linhas sequenciais
repetidas. Utilizando a opção -u, mostra apenas as linhas que não se
repetem.
cut
Imensamente utilizado em arquivos de script, corta (ou seja, exibe)
colunas ou campos selecionados a partir de um ou mais arquivos. O
arquivo-fonte não é modificado. Extremamente útil quando se necessita um
acesso rápido a um recorte vertical de um arquivo. Por padrão, os
recortes são delimitados por um caracter tab.
Opções frequentemente utilizadas:
- -b list – Exibe os bytes nas posições list;
- -c list – Exibe os caracteres nas colunas list;
- -d delim – Define o delimitador de campos para -f;
- -f list – Exibe os campos de list.
Exemplificando:
Visualizar os nomes de usuários (no primeiro campod delimitado por vírgula) de /etc/passwd:
# cut -d: -f1 /etc/passwd
paste
Concatena arquivos lado a lado, na forma de colunas:
# paste arquivo1.txt arquivo2.txt
join
Semelhante ao paste, entretanto trabalha especificando campos no formato join -1 CAMPO -2
CAMPO <arquivo um> <arquivo dois>, sendo, CAMPO é o
número indicando qual campo nos respectivos arquivos (primeiro e
segundo) deve ser correlacionado. Por exemplo, relacionar as linhas de
arq1, cujo primeiro campo (coluna 1) seja igual ao primeiro campo de
arq2:
# join -1 1 -2 1 arq1 arq2
sort
Ordena alfabeticamente um lista de arquvios. Utilizando a opção -n, ordena-se numericamente e -r inverte o resultado.
fmt
Formata o texto com uma extensão especificada, preenchendo linhas e
removendo caracteres da nova linha. Se forem especificados múltiplos
arquivos na linha de comando, eles serão concatenados.
Opções interessantes na utilização do comando descrito acima:
- -w : Indica o número de caracteres por linha;
- -s: Quebra linhas grandes, mas não as preenche;
- -u: Um espaço entre palavras e dois espaços entre sentenças.
pr
O comando pr imprime na tela o arquivo com paginação. Este comando
formata um arquivo texto para uma saída paginada com cabeçalho, margens e
largura definidos.
As opções mais utilizadas são:
- -a: Exibe colunas no sentido horizontal;
- -d: Expecifica espaçamento duplo;
- -l n: Formata o número de linhas na página para o valor n;
- -o n: Especifica o número de espaços da margem esquerda.
tr
Converte caracteres. Sua utilização difere-se dos comandos citados
anteriormente, pois os mesmos utilizam como entrada padrão ou indicando
um arquivo. O comando tr usa apenas a entrada padrão.
Exemplo: converter todas as letras minúsculas para maiúsculas:
# echo abc | tr ‘[a-z]‘ ‘[A-Z]‘
Com isso, encerramos mais um objetivo. No próximo artigo iremos abordar sobre o gerenciamento básico de arquivos.
***Artigo de Deividson Ludolf
|
Este artigo explica uma maneira de assinar os códigos dos seus
aplicativos internos, juntamente com seus instaladores. A assinatura de
código de seus aplicativos e instaladores fornece uma experiência de
usuário amigável do UAC durante a instalação, desinstalação, e quando os
aplicativos legados podem precisar ser executados com privilégios
administrativos (mais sobre privilégios administrativos abaixo).
Experiência de instalação amigável do UAC
A imagem abaixo mostra uma caixa de diálogo UAC amigável, completo
com o nome do Programa, Verifiedpublisher. Se os seus aplicativos
internos não são de código assinado, o usuário receberá um diálogo de
aviso, com um nome de programa bizarro, e Verifiedpublisher será
definido para desconhecido.
Eu não sei quanto a você, mas eu prefiro dar condição aos meus
usuários para ver diálogos UAC amigáveis, em vez do diálogo de aviso. De
repente, eles aprovaram “acidentalmente” um aviso UAC que pode causar
um grande problema.

Se você está assinando aplicativos que não são internos para a sua
organização, o conteúdo ao redor dos certificados e a orientação em
torno de signtool.exe podem violar as regras de assinatura de código de
organizações ou dos procedimentos.
Este artigo fala sobre a assinatura de código de aplicativos internos que serão utilizados na sua organização.
Certificado de assinatura de código
A primeira ordem de um negócio é obter um certificado de assinatura
de código instalado em máquinas que vão construir seus aplicativos
internos. Você pode notar na imagem abaixo que o meu servidor de
certificado gmcx-Security-CA emitiu um certificado de assinatura de
código e que o importei para a loja “Personal” no âmbito da pasta
“Certificates”.
Para ser honesto, a criação de um certificado de assinatura de código
exigiu a criação de um template de certificado no servidor de
certificado que me permitiu fazer isso. Eu achei este artigo do TechNet
muito útil:
http://technet.microsoft.com/en-us/library/cc731705(v=ws.10).aspx

Depois de criar o certificado, exporte-lo e imporeá-lo em todas as máquinas sob os usuários “Personal” armazenados como acima.
Por exemplo, eu tenho esse certificado instalado nas máquinas dos nossos desenvolvedores e dois no servidor de build.
Configurando a solução (projetos executáveis)
Existem várias maneiras de configurar as ações que ocorrem durante
MSBuilds. Eu escolhi o método do “arquivo batch” por ele ser muito fácil
de implementar e depurar. Você pode aproveitar um dos dois métodos não
convencionais e construir tarefas ou criar a sua própria tarefa de
compilação, mas eu escolhi “arquivos batch”, pelas razões acima.
Observe que verifiquei esses arquivos batch em controle de versão.
Isso garante que todas as máquinas podem construir a solução
corretamente.

AfterBuildTasksDebug.bat
Se o cenário requer que você faça uma assinatura de código da
compilação de depuração, o arquivo batch abaixo usa o programa
signtool.exe para a assinatura do código do programa .exe. Você
“poderia” também passar parâmetros de linha de comando para o arquivo
batch que inclui o nome da pasta do alvo, juntamente com o nome do alvo.
Preferi manter isso de uma forma simples para fazer com que ficasse
mais fácil de entender todas as partes.
Observe que eu não tinha que especificar um certificado, uma senha
etc. Isso porque eu só tenho um certificado de assinatura de código
instalado na minha máquina. O switch “/a” instrui signtool a escolher
automaticamente o código de certificado de assinatura de minha store
“Personal”.
@echo on
call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”
call signtool sign /a “C:\Projects\GMC\Src\GMC\bin\Debug\GMC.exe”
AfterBuildTasksRelease.bat e a pegadinha
Agora um tempo para uma pegadinha desagradável. Ela fez com que eu
gastasse cerca de duas horas tentando descobrir por que cada vez que eu
fazia uma compilação de lançamento utilizando o projeto de instalação
para construir e criar o pacote de instalação que o instalador do .exe
instalou não estava mais assinado.
Leia este tópico no Dev Center do Windows para obter mais detalhes: Setup project strips digital signature from exe target.
Agora que você já leu o tópico acima, vai compreender por que, ao
criar um release build, você deve assinar o código de .exe nas pastas
\obj e \bin.
O SignTool… controla a assinatura do meu exe. Deixe-me chamar um
interruptor signtool adicional que você precisa ter em mente quando
assinar o seu .exe.
Você também deve especificar o switch “/ t”. Isso colocará data e
hora em seu .exe para que o usuário saiba quando o .exe foi construído.
@echo on
call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”
call signtool sign /a /t http://timestamp.comodoca.com/authenticode
“C:\Projects\GMC\Src\GMC\obj\Release\GMC.exe”
call signtool sign /a /t http://timestamp.comodoca.com/authenticode
“C:\Projects\GMC\Src\GMC\bin\Release\GMC.exe”
Configurando o Visual Studio 2010 para usar os arquivos batch acima durante uma compilação

- Abra a caixa de diálogo Build Events na guia das propriedades do projeto .exe.
- Altere o “Executar o evento pós-compilação” para “Quando o compliador atualizar a saída do projeto”.
- Digite o texto acima na caixa de texto “pós-evento de compilação de linha de comando”.
Isso irá executar um dos dois arquivos batch com base na configuração, Debug ou Release.
Construindo a solução
Como muitos de vocês, eu não construí o meu Release Build dentro do
Visual Studio. Alguns usam um servidor de build, outros os constroem a
partir da linha de comando para permitir que outras tarefas sejam
realizadas.
Logo abaixo está um fragmento de um arquivo batch que gosto de usar
quando estou construindo um release build. O comando …devenv..
reconstrói a minha solução. Observe o switch “/rebuild” em vez do switch
“/build”.
O comando signtool … assina o meu instalador .msi que o projeto Setup
construiu. Deixe-me chamar dois switches signtool adicionais com os
quais você precisa se importar.
É importante que você especifique o switch “/d” para seus
instaladores .msi. Se você voltar até o topo deste artigo e olhar a
imagem UAC, verá que o nome do programa corresponde ao texto do switch
“/d” abaixo. Se você não especificar isso, o usuário verá um texto
bizarro.
Você também deve especificar o switch “/t” . Isso irá colocar data e
hora em seu instalador para que o usuário saiba quando o instalador foi
construído.
@echo on
call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”
devenv /rebuild Release /project GMC_Setup C:\Projects\GMC\Gmc.sln
echo .
echo .
pause
signtool sign /a /d “GMC for Office 2010 Setup” /t http://timestamp.comodoca.com/authenticode
C:\Projects\GMC\Src\GMC_Setup\Release\GMCForOffice2010_Setup.msi
… additional tasks
Aplicativos legados que rodam no Windows 7 e superiores
Minha empresa possui um aplicativo legado Windows Forms que foi
escrito durante a época do Windows XP. Minha empresa, como muitas
outras, nunca instalou o Windows Vista. Recentemente, o Windows 7 foi
instalado em nossos desktops corporativos.
Bem, os aplicativos legados da empresa que eu herdei fazem coisas que
não são amigáveis. Por exemplo, escrever para a pasta \Arquivos de
Programas e outras tarefas que são agora consideradas tabu para o
Windows 7.
Sendo um bom administrador de empresa e desenvolvedor, quero todos os
meus clientes executando o Windows 7 com o UAC com a configuração
padrão e que meus usuários aprendam sobre o recurso UAC e seus
benefícios; isso irá proporcionar-lhes um ambiente de computação mais
seguro aqui no trabalho e em casa.
A Microsoft documentou UAC aqui: http://msdn.microsoft.com/en-us/library/windows/desktop/aa511445.aspx
A Microsoft e os blogueiros têm documentado uma série de estratégias
para lidar com aplicativos UAC e legados. Transformar o UAC ou limitar
as suas capacidades não devem ser consideradas boas opções.
Eu não estava disposto a correr o risco de modificar nossos
aplicativos legados, então executei meus poucos aplicativos empresariais
com um manifesto de aplicativo incorporado que diz ao sistema
operacional que esse aplicativo requer privilégios de administrador para
ser executado. Todos os nossos usuários são administradores em seus
computadores locais.
Exemplo de manifesto do aplicativo
Observe o manifesto do aplicativo abaixo que o “requestExecutionLevel” é “requireAdministrator”.
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<assembly xmlns=”urn:schemas-microsoft-com:asm.v1″ manifestVersion=”1.0″>
<assemblyIdentity version=”1.0.0.0″ processorArchitecture=”X86″ name=”GMC” type=”win32″/>
<trustInfo xmlns=”urn:schemas-microsoft-com:asm.v3″>
<security>
<requestedPrivileges>
<requestedExecutionLevel level=”requireAdministrator”/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
Para incorporar o manifesto do aplicativo acima, você precisa usar o
programa mt.exe. Eu coloquei o comando abaixo no topo dos meus dois
arquivos batch, AfterBuildTasksDebug.bat e AfterBuildTasksRelease.bat.
Você vai precisar editar os caminhos e o nome .exe, bem como o nome do manifesto.
call “C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\mt.exe” -manifest
“C:\Projects\GMC\Src\GMC\GMC.exe.manifest”
-outputresource:”C:\Projects\GMC\Src\GMC\bin\Debug\GMC.exe;#1″
Fechamento
Para aqueles que têm a necessidade ou desejo de assinar os códigos de
seus aplicativos empresariais internos, espero que este artigo tenha
ajudado a evitar a longa curva de aprendizado.
Tenha um ótimo dia!
***
Texto original disponível em http://karlshifflett.wordpress.com/2012/04/16/coding-signing-internal-applications-and-a-gotcha/
|
Neste artigo, vou mostrar um pouco sobre o Vagrant,
apresentar um problema comum e a solução para ele. Os requisitos para
acompanhar o artigo são familiaridade com o assunto de virtualização,
não ter medo do shell e um pouco de paciência! Caso encontre algum erro
ou algo não tenha ficado muito claro em algum passo ou explicação, é só
postar nos comentários.
Muitos desenvolvedores gostam de ter um ambiente de fácil acesso para
simular testes da sua aplicação em ambiente parecido ao de produção
(OK! Não sei se são muitos, mas deveriam todos ter essa prática).
O Vagrant é uma solução para isso junto com o VirtualBox. Algo
estranho? Se eu tenho o VirtualBox, por que preciso do Vagrant também?
Eu posso fazer tudo com o VirtualBox!
Verdade! O VirtualBox já é uma solução para o problema, mas o Vagrant
tem recursos que não são fornecidos no VirtualBox, por exemplo,
configurações básicas para trabalhar com o Puppet ou Chef, fácil
configuração via Vagrantfile e o mais interessante para quem é desenvolvedor: um CLI amigável!
Então, o que eu preciso para começar a usar o Vagrant?
Tendo os requisitos citados devidamente configurados, recomendo criar
uma pasta com o nome da VM que pretende criar e configurar um ambiente
ruby para ela, assim:
host $ mkdir ubuntu
host $ cd ubuntu
host $ echo "rvm use 1.9.3" > .rvmrc
Talvez você precise entrar e sair da pasta do projeto para o RVM carregar o ambiente, caso você use muitas versões do ruby.
Feito isso, vamos agora instalar o Vagrant:
host $ gem install vagrant
Agora, temos o Vagrant instalado e precisamos criar nossa VM, mas para isso preciso de uma Box:
host $ vagrant box add lucid32 http://files.vagrantup.com/precise32.box
No exemplo acima, estou adicionando uma Box à minha máquina, no caso,
o Ubuntu Pricese 32 bits. Ok! Onde foi parar essa Box agora?
No meu caso, foi para /Users/joaovrmaia/.vagrant.d/boxes/precise32.
Eu uso Mac OS X, mas basicamente o que ele fazer é colocar na home do
seu usuário para que você possa reaproveitar o Box para outras VM. O
detalhe é que nesse caso estou pegando uma VM padrão do Vagrant, mas
nada impede você de criar a sua VM e compartilhar. Outra coisa: isso é
comum de acontecer para facilitar todos os desenvolvedores da equipe
terem o mesmo ambiente em suas máquinas. Vou deixar essa caso para outro
momento.
Show! Tenho VirutalBox, tenho Vagrant e tenho minha Box, mas cadê minha VM? Calma, jovem padawan!
host $ vagrant init precise32
Esse comando vai criar o Vagrantfile , que tem mais ou menos esta cara:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant::Config.run do |config|
# configurações vão aqui
config.vm.box = "precise32"
end
Agora sim já temos tudo para a tão esperada hora, iniciar a VM!
host $ vagrant up
[default] Attempting graceful shutdown of VM...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
Yey! VM funcionando, mas como acessar ela agora? Muito fácil: basta dar um ssh !
host $ vagrant ssh
vm $
Bom, agora sua VM está funcionando e você já está livre para se
divertir com ela, mas lembra que citei um problema e que apresentaria
sua solução?
Provavelmente, os seus primeiros passos serão:
vm $ sudo su
vm # apt-get update
vm # apt-get dist-upgrade
É claro, aproveitar que a VM está nova e deixá-la atualizada e sem
risco de quebrar nada! Ai que você se engana! Em toda atualização de
Kernel da VM ou do VirtualBox, o processo a seguir será necessário. Não
tive tempo de verificar mais a fundo o problema, mas ele é comum.
Ainda não ficou claro qual é o problema? Faça os seguintes passos:
vm $ exit
host $ vagrant reload
[default] Attempting graceful shutdown of VM...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!
mount -t vboxsf -o uid=`id -u vagrant`,gid=`id -g vagrant` v-root /vagrant
host $
OH WAIT! Algo de errado não esta certo! Pois é, esse é o problema! =/
Fique calmo que eu tenho a solução! =)
host $ vagrant ssh # sim, ela ainda funciona mesmo com o erro
vm $ sudo apt-get install build-essential -y # compiladores
vm $ sudo apt-get install linux-headers-server linux-headers-virtual -y # headers do kernel
vm $ sudo apt-get install kernel-package -y # pacotes do kernel
vm $ sudo apt-get install dkms -y # para o virtual box
vm $ mkdir vbox
vm $ wget http://download.virtualbox.org/virtualbox/4.1.12/VBoxGuestAdditions_4.1.12.iso
vm $ sudo mount -o loop VBoxGuestAdditions_4.1.12.iso vbox/
vm $ cd vbox
vm $ ./VBoxLinuxAdditions.run
Agora, basta sair da VM e fazer o reload que ela funcionará novamente sem erros! =)
O detalhe vai para o fail acusado ao rodar o binário VBoxLinuxAdditions.run do Xorg, mas caso não tenha ele instalado não é problema!
Fica agora aí com a sua VM funcionando de boa para as suas brincadeiras de SysAdmin! =)
Abraços! *** Artigo de João Víctor
|
Quantas vezes você já tentou clicar em um link de página de
Internet no seu documento feito no LibreOffice e não abriu no browser?
Creio que algumas vezes, não é mesmo? Já vi muitos usuários xingando e
dizendo que o LibreOffice não possuia esse recurso de clicar no link e
direcionar para um aplicativo externo. Na verdade, o recurso existe, mas
nem sempre o usuário lê o que está na tela – por favor, não se ofendam
por que escrevi isso, mas é o que de fato acontece. Ninguém nasce
sabendo, certo? Então, vou explicar como o usuário pode desabilitar essa
opção. Ela vem marcada como padrão, mas não é obrigatório usar desta
forma, então é possível personalizar.

Vejamos, hoje, quando o usuário instala o LibreOffice, esbarra nessa
questão. Acontece que existe uma opção de segurança marcada, que obriga o
usuário a apertar a tecla <CTRL> + o clique do mouse para abrir o
hyperlink. Vejamos o exemplo abaixo. Ao posicionar o cursor do mouse no
link, será exibida uma caixa com informações. Se o usuário seguir as
instruções, o hyperlink será aberto.

Pois bem, esse recurso foi implementado para facilitar o usuário na
hora de selecionar o hyperlink com o mouse para copiar o endereço. Vai
me dizer que nunca aconteceu contigo de clicar para selecionar o
endereço do hyperlink e um click sem querer ali, acabava abrindo o
aplicativo externo ? Foi pensando nisso que os desenvolvedores do
LibreOffice colocaram essa opção de segurança. Mas se você não gostar,
tudo bem, podemos desativar, vejamos como.
Vá no menu FERRAMENTAS-OPÇÕES:
Vá no item LIBREOFFICE-SEGURANÇA:
Clique no botão SEGURANÇA:

Desmarque a opção de segurança: Utilizar a tecla Ctrl junto com o
clique para abrir os hyperlinks. Clique no OK nesta janela e na janela
seguinte.
Pronto, a partir de agora se você clicar em um hyperlink, você será direcionado para o aplicativo externo. *** Artigo de Eliane Domingos de Sousa
|
Olá, pessoal! Antes de começar, gostaria de deixar claro que o
texto abaixo trata, na verdade, de um ponto de vista pessoal sobre
segurança. Obviamente, o texto dará foco à segurança da informação, mas
acredito que determinados pontos sejam adequados também para segurança
de forma geral.
Segurança
Se alguém me perguntar: “O que é segurança?”, eu provavelmente responderei, de bate pronto, com outra pergunta: “O que você quer segurar?”. A
resposta com uma outra pergunta, apesar de parecer evasiva, tem um
objetivo bastante direto: mensurar o valor da informação que precisa ser
segurada.
Vou tentar me explicar: em um cenário hipotético, temos uma
garotinha. Carolzinha é seu nome. Apesar de ter apenas 8 anos, ela adora
tecnologia, assim como adora os bichinhos de pelúcia que ganhou de seu
pai. Juntando o útil ao agradável, ela decidiu publicar, em um site
próprio, fotos de seus bichinhos de pelúcia em diversas ocasiões, para
poder mostrar para as amiguinhas. Ela possui um banco de dados com
centenas de fotos, dos mais variados bichinhos, nas mais variadas
situações. Esse banco de dados utiliza um hash MD5 para armazenar sua
senha.
Em outro cenário hipotético, temos uma instituição financeira, de
âmbito global, com uma carteira de clientes relativamente grande, que
fazem muitas transações, de alto valor monetário. Essa instituição
financeira utiliza um sistema extremamente complexo, que além de
controlar todas essas transações, ainda mantém um histórico detalhado de
cada transação, com data, local, valor, etc. Assim como o site da
Carolzinha, o sistema dessa instituição financeira também utiliza um
hash MD5 para armazenar as senhas de seus clientes.
O MD5, que foi desenvolvido em 1991, é um algorítimo de hash
(unidirecional) de 128 bits, que faz apenas uma passagem sobre os dados
e, por isso, é um hash com uma probabilidade relativamente alta de se
conseguir uma colisão, ou seja, duas mensagens diferentes, produzindo o
mesmo hash. Como é sabido que o MD5 é vulnerável, então podemos afirmar
que ele não é seguro, correto?
A questão é, qual o custo para se encontrar uma colisão em um hash
MD5 e qual o benefício daquilo que pode ser obtido? Será que esse custo
não é muito superior ao benefício que será obtido com a senha de uma
garotinha de 8 anos, cujo único conteúdo é uma base de dados com
centenas de fotos de bichinhos de pelúcia?
Então, vejo segurança como uma medida de custo. Quanto maior o
benefício daquilo que pode ser obtido, menor será sua segurança,
independentemente da técnica aplicada na segurança. Quando o custo para
se obter determinada informação for muito maior que a própria
informação, então podemos dizer, de certa forma, que a informação está
segura.
Sensação de segurança
Mesmo sabendo que seria necessário 1.7 x 10¹³ TB para armazenar todas
as possibilidades de um hash MD5, Fulano, que é desenvolvedor de um
gateway de pagamentos online, optou por utilizar um hash de 512 bits, da
família SHA-2, já que não há colisão nesse tipo de hash. Ao ser
questionado se os dados dos clientes do gateway estavam seguros, Fulano
respondeu com um grande SIM! Obviamente, a sensação de segurança
proporcionada pelo hash de 512 bits, foi o fator motivante para o sim.
Mas os dados estão mesmo seguros?
Vamos pensar em mais um cenário hipotético, de um site de uma rede de
cinemas, que possui um programa de fidelidade, onde os clientes
cadastrados ganham descontos progressivos, conforme utilizam os serviços
da empresa. Esse site, por negligência, ou por acreditar que seus dados
não tem tanto valor, armazena as senhas de seus clientes de forma plana
no banco de dados.
Beltrano, um grande fã de cinema, além de ter um cadastro no site da
rede de cinemas, também tem um cadastro na empresa de gateway de
pagamentos. Beltrano, por desinformação, ou mera comodidade, assim como
muitos outros usuários, utiliza a mesma senha no site do cinema e no
gateway de pagamentos online.
Apesar do gateway de pagamentos online utilizar uma técnica avançada,
que garante um alto custo para se obter uma informação, a segurança dos
dados desse gateway pode ser comprometida pela ausência de segurança no
armazenamento dos dados do site da rede de cinemas.
Transformar sensação de segurança em segurança, ao meu ver, não
depende apenas das técnicas empregadas para segurar a informação, mas de
políticas adotadas ao manter a informação. Fulano foi precipitado ao
afirmar que os dados estavam seguros, pois o gateway de pagamentos não
possui nenhuma política definida para renovação das credenciais de seus
clientes.
Como em um sistema de informação, qualquer pessoa pode se passar por
qualquer outra pessoa, a ausência de uma política de renovação de
credenciais, fez com que algo teoricamente seguro, passasse a ser apenas
sensação de segurança, mas que na prática, pode comprometer todo um
conjunto de técnicas empregadas na armazenagem da informação.
Conclusão
A segurança em sistemas de informação não está apenas relacionada com
identificação, autenticação e autorização. Assim como a segurança na
armazenagem dos dados não está apenas na técnica de criptografia
empregada, acesso físico ao servidor, etc.
Penso que segurança está bastante relacionada com políticas
empregadas no processo de identificação e autenticação, armazenagem, mas
também na renovação de credenciais. Quanto mais antiga for uma mesma
credencial, mais vulnerável ela pode ser.
Então, da mesma forma que quanto maior o valor da informação, menos
segura ela estará, quanto mais antiga for uma credencial, menos segura
ela será. De certa forma, penso que uma política de renovação de
credencial quizenal, por exemplo, pode trazer mais segurança para os
dados de uma aplicação, que a própria utilização de uma técnica mais
avançada de criptografia e acesso limitado aos servidores.
|
Dados do mercado brasileiro de tecnologia apontam para uma tendência que parece definitiva: vamos todos nos tornar mobile. Estudos colocam o Brasil como décimo maior mercado de smartphones do mundo.
O ‘boom’ dos dispositivos móveis estimula diretamente o
desenvolvimento do mercado de aplicativos: o Brasil já é o maior mercado
de apps da América Latina e vem despertando o surgimento de um novo
nicho de investimentos focado na área. Nesse sentido, a expectativa é
que o mercado mobile domine o segmento de TI até 2015 e seja responsável
por mais de 50% do faturamento mundial da área. Tudo isso graças a uma
quebra de paradigma de computação e acesso à informação.

A aposta nos altos números para o Brasil não é em vão: desde que a
Apple liberou a parte de jogos da App Store no Brasil, em abril do ano
passado, as receitas do site cresceram 80%, parte justificada pela larga
presença de brasileiros em atividade nas redes sociais, que ocupam
quarto lugar nas redes no mundo. Essa participação massiva é apontada
como decisiva para o aculturamento do uso de apps no Brasil acima das
médias mundiais, já que a percepção das funcionalidades extras dos
smartphones acontece, na maioria das vezes, através do contato com
usuários já iniciados.
Nesse contexto, a facilidade de se produzir aplicativos com baixo
custo de investimento inicial e os jovens milionários que surgem na área
a cada dia – como o brasileiro Mike Krieger, co-criador do Instagram
que faturou, com 24 anos, 182 milhões com a venda do aplicativo para o
Facebook – inspiram o surgimento de interessados no negócio. A formação
técnica da mão de obra brasileira, considerada de ótima qualidade,
associada a uma remuneração abaixo dos patamares internacionais também
são fatores que apontam para um mercado que tem tudo para vingar. Mas,
ainda assim, a produção nacional ainda é baixa: apenas 1,4% dos
aplicativos produzidos no mundo são brasileiros, segundo a plataforma
AppsGeyser.
Muito disso se deve ao fato de que a formação de uma empresa
desenvolvedora de apps não é tão simples quanto parece, e exige que os
executivos tenham um modelo de negócios bem estabelecido. O primeiro
passo fica por conta da formação de uma boa equipe multidisciplinar, que
inclua analistas desenvolvedores, web designers, redatores e
ilustradores. Nesse momento, a atenção é voltada tanto para busca
daqueles que tenham conhecimentos específicos para cada plataforma
(Apple, Android, WindowsPhone, BlackBerry etc.), quanto para a retenção
de talentos, já que o mercado é forte e os bons profissionais são
disputados de forma acirrada. Os executivos também devem ficar atentos a
questões como utilização de hardwares específicos e a obtenção de
certificações para comercialização dos aplicativos.
Entre os modelos de negócios mais comuns, quatro deles merecem
destaque e podem gerar receita e rentabilidade expressiva garantindo
crescimento acelerado – fator fundamental para atrair investidores. Um
modelo possível é a venda de apps no varejo, diretamente nas lojas
virtuais e a preços normalmente baixos, sendo a grande maioria entre U$
0,99 e U$ 4,99, ou a venda para empresas e patrocinadores, gerando apps
gratuitos nas lojas virtuais. A vantagem de ambos os modelos é que a
apresentação pode ser mundial e sem grandes dificuldades, fazendo com
que a quantidade de downloads atinja facilmente a casa de milhares e,
por vezes, de milhões, viabilizando o projeto.
No caso de apps comercializados no varejo, a loja virtual fica com um
percentual da receita e o restante é repassado para a empresa
desenvolvedora. No caso do app de distribuição gratuita, a empresa
contratante ou o patrocinador remunera o trabalho de desenvolvimento do
projeto, que pode variar de R$ 5.000 a R$ 150.000 embora, em função da
complexidade, o projeto possa chegar a cifras da ordem de R$ 500.000. O
app pode também ser comercializado em valores mensais e sem valores de
aquisição.
Existe ainda a possibilidade de venda de espaço publicitário dentro
dos apps, chamado de in-apps. Nesse caso, podem ser disponibilizados
banners, rodapés, telas de entrada e espaços diversos. A gestão de
anunciantes de apps é feita pelas lojas virtuais que cobram dos
anunciantes e repassam parte da receita para a empresa desenvolvedora ou
a própria desenvolvedora pode fechar acordos com os patrocinadores
interessados diretamente.
Por fim, há ainda a possibilidade de venda de “novos recursos” dentro
dos apps. Por exemplo, podemos baixar gratuitamente um app que contenha
inúmeras funcionalidades “básicas” e que, caso tenhamos interesse,
podemos disponibilizar funcionalidades “avançadas” cobrando por isso.
O importante é considerar que o mercado de aplicativos se adapta bem
ao nosso novo mundo sem barreiras: em todos os casos, não há necessidade
de contato físico ou deslocamento para um determinado local geográfico.
Já o retorno do capital investido depende de inúmeros fatores, como: a
modalidade de comercialização escolhida, a especialização dada ao
negócio e o tamanho da equipe contratada.
|
Em um artigo anterior, demonstrei a aplicação da anotação @Cacheable do Spring 3.1, que é usada para marcar os métodos cujos valores de retorno serão armazenados em um cache. No entanto, @Cacheable é apenas uma de um par de anotações que os caras do Spring criaram para o cache, a outra sendo @CacheEvict.
Como @Cacheable, o @CacheEvict também possui os atributos value, key e condition. Eles funcionam exatamente da mesma maneira como aqueles suportados por @Cacheable. Para mais informações sobre eles dê uma olhada no meu artigo anterior.
O @CacheEvict suporta dois atributos adicionais: allEntries e beforeInvocation. Se eu fosse um apostador, eu apostaria meu dinheiro no allEntries como o mais popular. Ele é usado para limpar completamente o conteúdo de um cache definido pelo valor obrigatório do argumento do @CacheEvict. O método a seguir demonstra como aplicar allEntries:
@CacheEvict(value = "employee", allEntries = true)
public void resetAllEntries() {
// Intentionally blank
}
resetAllEntries() define o atributo allEntries do @CacheEvict para “true” e, assumindo que o método FindEmployee (…) fique assim:
@Cacheable(value = "employee")
public Person findEmployee(String firstName, String surname, int age) {
return new Person(firstName, surname, age);
}
… então, no código a seguir, resetAllEntries() irá limpar o cache “employees”. Isso significa que, no teste JUnit abaixo, employee1 não vai referenciar o mesmo objeto como employee2:
@Test
public void testCacheResetOfAllEntries() {
Person employee1 = instance.findEmployee("John", "Smith", 22);
instance.resetAllEntries();
Person employee2 = instance.findEmployee("John", "Smith", 22);
assertNotSame(employee1, employee2);
}
O segundo atributo é o beforeInvocation. Ele determina quando ou não um item de dados é limpo do cache antes ou depois de seu método ser invocado.
O código abaixo é muito sem sentido; no entanto, ele demonstra que você pode aplicar simultaneamente @CacheEvict e @Cacheable a um método.
@CacheEvict(value = "employee", beforeInvocation = true)
@Cacheable(value = "employee")
public Person evictAndFindEmployee(String firstName, String surname, int age) {
return new Person(firstName, surname, age);
}
No código acima, o @CacheEvict exclui quaisquer entradas no cache com uma chave correspondente antes de @Cacheable fazer buscas no cache. Já que o @Cacheable
não vai encontrar as entradas, ele chamará o meu código, armazenando o
resultado no cache. A chamada subsequente a meu método invocará @CacheEvict, que irá apagar todas as entradas apropriadas, resultando que, no teste JUnit abaixo, a variável employee1 nunca fará referência ao mesmo objeto que employee2:
@Test
public void testBeforeInvocation() {
Person employee1 = instance.evictAndFindEmployee("John", "Smith", 22);
Person employee2 = instance.evictAndFindEmployee("John", "Smith", 22);
assertNotSame(employee1, employee2);
}
Como eu disse acima, evictAndFindEmployee(…) parece um pouco sem sentido quando estou aplicando @Cacheable e @CacheEvict
ao mesmo método. Mas, é mais que isso, ele torna o código confuso e
quebra o princípio da responsabilidade única; daí eu recomendo criar
separadamente os métodos cacheable e cache-evict. Por exemplo, se você
tem um método que está fazendo cache, tal como:
@Cacheable(value = "employee", key = "#surname")
public Person findEmployeeBySurname(String firstName, String surname, int age) {
return new Person(firstName, surname, age);
}
Então, assumindo que você precisa de um controle de cache mais
agradável do que um simples “clear-all ‘, você pode definir facilmente
uma contrapartida:
@CacheEvict(value = "employee", key = "#surname")
public void resetOnSurname(String surname) {
// Intentionally blank
}
Este é um simples método blank marker que utiliza a mesma expressão SPEL que foi aplicada ao @Cacheable para despejar todas as instâncias Person a partir do cache, onde a chave corresponde ao argumento “surname”.
@Test
public void testCacheResetOnSurname() {
Person employee1 = instance.findEmployeeBySurname("John", "Smith", 22);
instance.resetOnSurname("Smith");
Person employee2 = instance.findEmployeeBySurname("John", "Smith", 22);
assertNotSame(employee1, employee2);
}
No código acima, a primeira chamada para findEmployeeBySurname(…) cria um objeto Person, o qual Spring armazena no cache “employee” com uma chave definida como: “Smith”. A chamada para resetOnSurname(…) apaga todas as entradas do cache “employee” com um sobrenome “Smith” e, finalmente, a segunda chamada para findEmployeeBySurname(…) cria um novo objeto Person, que o Spring novamente armazena no cache “employee” com a chave ” Smith “. Assim, as variáveis employee1 e employee2 não fazem referência ao mesmo objeto.
Já que eu abordei as anotações do cache Spring, a próxima peça do
quebra-cabeça é dar uma olhada na criação de um cache prático: como é
possível habilitar o cache do Spring e qual implementação de cache você
deve usar?
***
Texto original disponível em http://www.captaindebug.com/2012/09/spring-31-caching-and-cacheevict.html#.UPBWb2_7KSo
|
Esta é a primeira parte do primeiro de uma série de artigos sobre a biblioteca HLearn
para haskell nos quais tenho trabalhado nos últimos meses. A ideia da
biblioteca é mostrar que álgebra abstrata – especificamente monóides, grupos e homomorfismos
– é útil não apenas na programação esotérica funcional, mas também
problemas de aprendizado de máquina no mundo real. Em particular, nós
temos três coisas de graça ao elaborar um algoritmo de aprendizagem de
acordo com estas propriedades algébricas: (1) uma versão online do
algoritmo, (2) uma versão paralela do algoritmo, e (3) um procedimento
para cross-validation que funciona de modo assintótico mais rápido do
que a versão padrão.
Vamos começar com o exemplo de uma distribuição Gaussiana.
As distribuições Gaussianas são onipresentes em algoritmos de
aprendizado porque descrevem com precisão a maioria dos dados. Mas,
ainda mais importante, elas são fáceis de trabalhar, são totalmente
determinadas pela sua média e variação, e esses parâmetros são fáceis de
calcular.
Neste artigo, começaremos com exemplos de por que as propriedades
monóide e grupo de distribuições Gaussianas são úteis na prática. Depois
daremos uma olhada na matemática subjacente a esses exemplos e,
finalmente,veremos que essa técnica é extremamente rápida na prática e
resulta em paralelização quase perfeita.
HLearn como exemplo
Instale as bibliotecas a partir de um shell:
$ cabal install HLearn-distributions
Em seguida, importe as bibliotecas HLearn em um arquivo haskell:
> import HLearn.Algebra
> import HLearn.Models.Distributions.Gaussian
E algumas bibliotecas para podermos comparar o nosso desempenho:
> import Criterion.Main
> import Statistics.Distribution.Normal
> import qualified Data.Vector.Unboxed as VU
Agora vamos criar alguns dados para trabalhar. Para simplificar,
usaremos um conjunto de dados inventado sobre quanto dinheiro as pessoas
ganham. Cada entrada representa uma pessoa recebendo o salário. (Usamos
um pequeno conjunto de dados aqui para facilitar a explicação.)
> gradstudents = [15e3,25e3,18e3,17e3,9e3] :: [Double]
> teachers = [40e3,35e3,89e3,50e3,52e3,97e3] :: [Double]
> doctors = [130e3,105e3,250e3] :: [Double]
Para treinar uma distribuição Gaussiana a partir dos dados, nós simplesmente utilizamos a função train, desta maneira:
> gradstudents_gaussian = train gradstudents :: Gaussian Double
> teachers_gaussian = train teachers :: Gaussian Double
> doctors_gaussian = train doctors :: Gaussian Double
A função train é um membro da HomeTrainer Type Class, sobre a qual
falaremos mais adiante. Além disso, agora que treinamos algumas
distribuições Gaussianas, é possível realizar todos os cálculos normais
que possamos querer fazer em uma distribuição. Por exemplo, pegar média,
desvio padrão, pdf e cdf.
Agora vamos passar para os bits interessantes. Começaremos mostrando
que o Gauss é um semigrupo. Um semigrupo, por sua vez, é qualquer
estrutura de dados que possui uma operação binária associativa chamada
(<>). Basicamente, podemos pensar (<>) como adicionando ou
agrupando as duas estruturas juntas. (Semigrupos são monóides com apenas
uma função mappend.)
Então, como usaremos isso? Bem, e se decidimos que desejamos uma
distribuição Gaussiana sobre os salários de todos? Utilizando a
abordagem tradicional, teríamos que recalcular isso a partir do zero.
> all_salaries = concat [gradstudents,teachers,doctors]
> traditional_all_gaussian = train all_salaries :: Gaussian Double
Mas isso só repete o trabalho que já fizemos. Em um conjunto de dados
do mundo real, com milhões ou bilhões de amostras, isso seria muito
lento. Melhor seria mesclar a distribuições Gaussianas que já treinamos
em uma Gaussiana final. Podemos fazer isso com a operação semigrupo
(<>):
> semigroup_all_gaussian = gradstudents_gaussian <> teachers_gaussian <> doctors_gaussian
Agora,
traditional_all_gaussian == semigroup_all_gaussian
A parte mais legal disso é que o funcionamento da operação semigrupo
leva tempo O (1), não importa a quantidade de dados que já treinamos nas
distribuições Gaussiana. A abordagem simples leva o tempo O (n), então
temos uma velocidade consideravelmente grande!
Em seguida, um monóide é um semigrupo com uma identidade. A
identidade de uma distribuição Gaussiana é fácil de definir,
simplesmente aplique train ao conjunto de dados vazio!
> gaussian_identity = train ([]::[Double]) :: Gaussian Double
Agora,
gaussian_identity == mempty
Mas ainda temos mais um truque na manga. A distribuição Gaussiana não
é apenas um monóide, mas também um grupo. Os grupos aparecem o tempo
todo na álgebra abstrata, mas não demos muita atenção à programação
funcional por algum motivo. Bem, grupos são simples: eles são apenas
monóides com um inverso. Esse inverso nos permite fazer a “subtração” em
nossas estruturas de dados.
Então, de volta ao nosso exemplo de salário. Vamos supor que nós
calculamos todos os nossos salários, mas já percebemos que incluir
estudantes de graduação nos cálculos de salário foi um erro (eles não
são pessoas reais, na verdade). Em uma biblioteca normal, teríamos que
recalcular tudo do zero novamente, excluindo os alunos de graduação:
> nograds = concat [teachers,doctors]
> traditional_nograds_gaussian = train nograds :: Gaussian Double
Mas, como já discutimos antes, isso leva muito tempo. Podemos usar a
função inverse para fazer essa mesma operação em tempo constante:
> group_nograds_gaussian = semigroup_all_gaussian <> (inverse gradstudents_gaussian)
E agora,
traditional_nograds_gaussian == group_nograds_gaussian
Mais uma vez, nós convertemos uma operação que teria levado o tempo O
(n) para uma que leva o tempo O (1). Não pode ficar melhor do que isso!
A classe tipo HomTrainer
Como eu já mencionei, a HomeTrainer Type Class é a base da biblioteca HLearn.
Basicamente, qualquer algoritmo de aprendizagem que é também um
homomorfismo de semigrupo pode ser feito de um exemplo de HomTrainer.
Isso significa que se xs e ys constituem listas de pontos de dados, a
classe obedece à seguinte lei:
train (xs ++ ys) == (train xs) <> (train ys)
Isso pode ser mais fácil de ver em uma imagem:

No lado esquerdo, temos alguns conjuntos de dados e, no lado direito,
temos as distribuições Gaussianas correspondentes e os seus parâmetros.
Pelo fato de o treinamento da Gaussiana ser um homomorfismo, não
importa se seguirmos os caminhos laranja ou verde para chegarmos à nossa
resposta final. Nós chegaremos exatamente à mesma resposta de qualquer
maneira.
Com base apenas nessa propriedade, obtemos as três propriedades
“grátis” que mencionei na introdução. (1) Temos um algoritmo online
gratuito. A função add1dp pode ser utilizada para adicionar um novo
ponto único a uma distribuição Gaussiana existente. Digamos que eu tenha
me esquecido de um dos alunos de graduação – tenho certeza de que isso
nunca aconteceria na vida real – eu posso adicionar o seu salário assim:
> gradstudents_updated_gaussian = add1dp gradstudents_gaussian (10e3::Double)
Essa Gaussiana atualizada é exatamente o que conseguiríamos se
tivéssemos incluído o novo ponto de dados no conjunto de dados original.
(2) Recebemos um algoritmo paralelo. Podemos usar a função parallel
mais elevada para paralelizar qualquer aplicação de train. Por exemplo:
> gradstudents_parallel_gaussian = (parallel train) gradstudents :: Gaussian Double
A função parallel detecta automaticamente o número de processadores
que o seu computador tem e distribui uniformemente a carga de trabalho
neles. Como veremos na seção de desempenho, isso resulta na
paralelização perfeita da função de treinamento. A paralelização,
literalmente, não poderia ser mais simples!
(3) Obtemos a cross-validation de forma assintótica mais rápida, mas
isso não é aplicável realmente a uma distribuição Gaussiana, então vamos
ignorar isso aqui.
Um último comentário sobre a classe HomTrainer: nós nunca temos
realmente que definir a função train para o nosso algoritmo de
aprendizagem de forma explícita. Tudo o que temos que fazer é definir a
operação semigrupo, e o compilador vai deduzir a nossa função de
treinamento pra gente!
Na segunda parte do artigo, vamos dar uma olhada em como é o funcionamento da operação semigrupo da distribuição Gaussiana.
***
Texto original disponível em http://izbicki.me/blog/gausian-distributions-are-monoids#comment-988
|
Olá, pessoal! Nessa série de artigos sobre Agile/Scrum, vou
trazer pontos pelos quais acredito que todo Agilista tenha passado
quando começou a falar de Agile para alguém ou para um time que segue a
linha “no agile here”.
O que todo Agilista sofre:
- Vira motivo de risada: todos dão risada dele e dizem: “ele acha que a metodologia Agile é a bala de prata e vai mudar o mundo”.
Na verdade o Agilista que deveria rir, porque ele conseguiu “mudar” e
aqueles profissionais que são resistentes a qualquer tipo mudança estão
com os dias contados;
- Ser ignorado: todo agilista é ignorado no início;
- No bugs: associam que um agilista acredita que, ao
desenvolver um software usando metodologias ágeis, não se cria bugs.
Ninguém realmente diz isso, porém a acusação sobre o coitado do agislita
é servera;
O que os demais acreditam:
- Que a forma que têm usado até hoje é a correta, senão o projeto não
existiria, porém se esquecem que se existe até hoje, talvez seja por
consequência;
- Que software sem bug tem algo de errado e que alguma das
funcionalidades não foi implementada, pois não é possível desenvolver
software sem bug;
- Aumentar a cobertura de unit tests depois do código já escrito é sinonimo de qualidade.
Para começar, vamos falar sobre qualidade externa e interna de quando
vamos desenvolver um produto. Vamos lá, me responda com sinceridade:
algum cliente seu já pediu para você reduzir um pouco a sua estimativa
para entregar alguma tarefa? Se sua resposta foi sim, você já sabe sobre
o que vamos falar: como convencer o cliente que a qualidade não é
negociável? Vou explicar em detalhes ao longo do artigo.
Starting
Quem me acompanha aqui ou no twitter, já percebeu que eu tenho me
dedicado ao mundo Agile. O que vou falar aqui não está só ligado a ele,
mas foi onde eu consegui perceber isso de forma mais face-to-face
com o cliente e de certo modo foi onde houve menos questionamentos por
parte dele e até uma aceitação de mudanças sem muita discussão. Eu
sempre sofri com esse mal (desde da época de freelance) do cliente pedir
para mudar uma estimativa, porém ele não queria mudar o escopo dele e
sabemos que isso não é nada bom. Mas, como contornar a situação sem
gastar muito tempo? Para isso é preciso ter duas coisas bem claras em
mente:
- Qualidade externa: aquilo que o cliente vê, tem acesso, que é o front-end, lentidão, etc.
- Qualidade interna: aquilo que o cliente não tem acesso, tais como: refactoring, covertura de testes, code clear etc.
Quando o cliente pede para reduzirmos a estimativa, ele está afetando
a qualidade interna, algo como: “Sei que você tem a melhor equipe, com
os melhores profissionais, será que não dá para fazer em 1 ou 2 dias a
menos (isso aqui dá -16 hrs de trabalho, o que é muita coisa)?”.
Normalmente não dá para mudar isso, pois nós sabemos do impacto. E como
resolver isso?
Resposta ao cliente
Podemos perguntar ao cliente se o escopo não pode ser alterado, que
aquela parte onde temos as mensagens iterativas com o usuário não
poderia ficar para o futuro e que, por agora, trataríamos com mensagens
mais simples possível, por exemplo. Ou mudar o nível de importância,
assim isso impactará em outras e saberemos o que deve ser entregue
primeiro e isso forçará o product owner mover o backlog. Mas
abrir mão da qualidade interna é algo que não deve ser feito, pois já
sabemos dos problemas que vamos encontrar e o cliente não vai levar em
conta essa redução de estimativa quando os problemas surgirem,
principalmente se estes afetarem o “bolso dele”. Pense: “uma vez que se
penetra que uma base de código se deteriore, é muito dificil recuperar a
qualidade mais tarde”.
Um sistema com alta qualidade interna pode ainda ter baixa qualidade
externa, porém um com baixa qualidade interna raramente terá uma
qualidade externa alta, ou seja, não dá para construir algo bom se a
base está pobre, então daí que dizemos que a qualidade interna
simplesmente não é negociável.
Vou ficando por aqui. Espero que tenham gostado.
Abraços, see ya!
|