Author Archives: admin

Continuous Feedback Score

poucos dias houve um post d[x] Coraline Ada, um[x] dev que trabalhou no github e provocou mais uma longa discussão sobre a já sofrível relação de trabalho nos dias de hoje com o aumento da complexidade social e a divulgação imediata dos assédios.

Não vou entrar no mérito das discussões e pular direto pra sugestões de como enfrentarmos os problemas. Negar que sempre houve assédio nas relações de trabalho não funciona, mesmo quando achávamos que não existia racismo, homofobia, machismo, entre outras coisas.

Como se precaver?

Como fica a empresa diante de todas essas denúncias e a exposição de sua marca?

Lembre que a marca (brand) perde valor, o humor dos funcionários (ou colaboradores, pra incluir todos os credos) cai e como consequência a produtividade, a cobrança dos clientes intensifica por uma expectativa de resolução e lá se sabe quais mais prejuízos em cada confusão instaurada.

Uma saída encontrada e praticada para as empresas é criarem programas de recuperação da situação, o mais famoso é um programa de contenção depois que aconteceram os problemas, o Performance Improvement Plan (doravante denominado PIP).

Mas um ponto que entendemos, se a pessoa entrou em PIP, algum prejuízo já aconteceu. Piora se quem for fazer coaching/acompanhamento for do mesmo time e estrutura, porque alguma carga pessoal já existe.

Transparência

Lembra do NPS?

Então, se não lembra ou não conhece, a grosso modo de explicar é uma métrica pra saber a lealdade dos seus cliente, existe uma versão pra medir a lealdade também dos funcionários.


É bacana pra acompanhar o gráfico de quem está tendencioso a entrar em PIP. O acompanhamento da variação do seu NPS já é um forte indicador do humor em relação a empresa e aos pares.

O ideal é que cada um saiba sua nota e os objetivos claros que estão sendo mensurados, pelo menos pra abrir uma rodada de 1 pra 1 com seus pares ou superiores antes que o problema aconteça.

Mas isso não é o suficiente para identificar possíveis problemas, quanto de carga emocional existe nas relações que não consigo pegar no eNPS?

Processos subjetivos

Já trabalhei em times que medíamos frequentemente e cometemos o deslize de não desligar quando ultrapassava o ponto de recuperação por ignoramos o gráfico de acompanhamento dos resultados, isso causa um problema de contaminação na equipe.

Basta um insatisfeito por longo tempo pra causar um descontentamento geral (citation needed).

Alguns pontos são urgentes e difíceis de medir num processo objetivo e, quando já viu, passou daquele ponto de chamar pra conversa e evitar o PIP.

As vezes o time que é inadequado

Já trabalhei em equipes que trocamos algumas pessoas com times diferentes e funcionaram muito bem com outros pares, acontece. Não tem como evitar o aspecto cultural que se forma e cobrar inclusão irrestrita é incorrer em outros erros (polêmica pra post próprio).

O ideal que a própria equipe tenha autonomia necessária para rodar o seu processo de acompanhamento, sem a necessidade da empresa se envolver, mas para isso os líderes e board de direção precisam garantir.

Como meço o subjetivo?

Pra abrir uma rodada de processo subjetivo ou pré-PIP, não precisa de muita coisa, um responsável por coordenar abre uma campanha de feedback ao menor sinal de insatisfação (Come on baby, você sabe do que estou falando, aquelas conversas no café).

Basta todos informarem 3 (magic number) pontos negativos que incomodam naquela pessoa mesmo que os indicadores objetivos estejam sinalizando uma normalidade com menos detratores.


Computa-se os 3 mais relevantes e estabelece Keys objetivas ou claras para dar tempo de trabalhar a recuperação e esclarece o avaliado.



Em uma segunda rodada de avaliação (um ou dois meses depois) se mede o resultado alcançado.


Como escrevi anteriormente, existem pontos que são comportamentais e culturais que afetam as relações e nenhum dos dois lados estão dispostos a mudarem.

O que resta pra empresa é agir antes que aconteça o inevitável e blindar o time inteiro.

Que momento é adequado pra rodar o Feedback subjetivo?

Depende da estrutura da empresa, pode ser um líder técnico que identifica ou o próprio funcionário que sente algo diferente, aí depende.

Transparência e autonomia são as chaves, talvez só trabalhar isso já resolva o problema.

Transformando seu código de negócio em biblioteca versionada

Um problema comum no Frontend é o gerenciamento e organização do código e as últimas tecnologias nos últimos anos nos ajudam a resolver.

Caso

Tenho um código que depende de mapas em várias telas do sistema e organizei um componente que pode ser importado em vários arquivos.

Como esse componente tem um ciclo de desenvolvimento diferente, organizei como submódulo no git.


Para facilitar, os devs importam o projeto principal com parâmetro pra já carregar os submódulos, mas no final de contas fica tudo num mesmo lugar.

git clone --recursive -j8 git@github.com:cmilfont/beerswarm.git

Problema

O código está blindado para importar as dependências sem se preocupar com estrutura e organização, já que nos foi dada com a nova abstração na linguagem — transpilada pelo Babeljs — para funcionar em todos os navegadores, algo como:

import { BMap, Toolbar, GoogleMutant, GoogleApiLoader } from '/components/maps';

O problema mesmo é no ciclo de versão desses componentes. Se um desenvolvedor move um método de lugar e o projeto não tem 100% de cobertura em testes (se tratando de legado é o normal e esperado) corre o risco provável de detectar apenas em produção.

Problema dobrado, uso o Leaflet como gerenciador de mapas, cada fornecedor representa uma camada (layer) a ser exibido, o default é o Open Street Maps.

Para usar o mapa do Google teria que implementar uma layer e carregar a API, causou o problema com outra tela que precisava além do Mapa também carregar a biblioteca de places que faz parte dos opcionais. Daí nasce o submódulo do submódulo pra gerenciar.

Problemas secundários que também tomam tempo da equipe: merges desmotivantes.

Solução

Transformar esses códigos genéricos em bibliotecas com seu próprio ciclo de versionamento usando o próprio gerenciador de pacotes do Nodejs, o npm, como fazem as bibliotecas OpenSource da linguagem.

Hospedando o projeto da lib

Começamos por isolar a Layer do Google a ser usada no Leaflet como uma lib.

Usando o create-react-app (troque pelo seu boilerplate preferido) eu criei um projeto novo https://github.com/produtoreativo/react-leaflet-googlemutant, adicionei repositorio no github.

Formato 1: Open Source

Se não tem diferencial pro meu negócio (como uma Layer para o mapa do Google) o melhor é deixar o mundo ajudar a manter, reservando um repositório no npmjs.com.

Formato 2: Privado no npmjs.com

O registro global de libs no nodejs tem planos pagos para libs privadas, tem também que colocar private: true no package.json do projeto. Conveniente por ser a mesma coisa do OpenSource, mas talvez um preço salgado dependendo do tamanho da sua companhia.

Formato 3: Privado e hospedado in-house.

Caso queira hospedar seu próprio repositório de bibliotecas, pode usar uma opção como o Nexus e apontar no package.json o caminho como a própria documentação da ferramenta ensina.

Formato 4: Privado sem gerenciador de repositórios de libs

Caso ainda não queira configurar um servidor privado ou pagar o registro público global, pode também indicar no package.json o caminho ao github diretamente, algo como:

{
"name": "beerswarm",
"version": "0.1.0",
"private": true,
"dependencies": {
/* libs ... */
"react-leaflet-googlemutant": "github:produtoreativo/react-leaflet-googlemutant",
},
"devDependencies": {
"react-scripts": "0.9.5",
},
"scripts": {
"start": "NODE_PATH=src react-scripts start",
"build": "NODE_PATH=src react-scripts build && sw-precache --config=sw-precache-config.js",
"test": "NODE_PATH=src react-scripts test --env=jsdom --coverage",
"eject": "react-scripts eject"
}
}

Os devs que tiveram em uma máquina com permissão para puxar desse repositório no seu fornecedor git bastarão executar o npm install (ou yarn install) para ter as libs no projeto principal como dependência.

Lembrando que esse último caso de apontar diretamente para o github (ou gitlab) só funciona — como demonstra a própria documentação — informando qual commit ou branch no final da url com o pattern #commit-ish.

A versão informada no package.json fica só simbólica nesse caso e não define que versão real foi puxada.

Estrutura da Lib


Com o seu boilerplate preferido — no meu caso o create-react-app — crie a estrutura do seu projeto e reserve uma pasta (sugestão, chamei de lib) para o resultado final que será empacotado.

Basicamente precisamos configurar adequadamente o package.json e usar um Module Bundler (construtor que vai transformar seu código em um projeto executável no navegador) como Webpack.

Quero transformar o import em algo como:

import { GoogleMutant, GoogleApiLoader } from 'react-leaflet-googlemutant';

Configurando o package.json

Duas coisas importantes a configurar logo de início, o número de versão da lib e de forma recomendável o script que vai ser carregado quando essa lib for importada.

{
"name": "react-leaflet-googlemutant",
"description": "React leaflet wrapper to GoogleMutant plugin",
"version": "0.1.6",
"main": "./lib/react-leaflet-googlemutant.js",
"private": false
}

Ou seja, quando o usuário faz um import from ‘lib’. Essa Lib vai ser carregada no que você informar em main.

Utilizei a lib standard-version para gerenciar as mudanças do número de versão de forma automática.

Outro fator importante de configuração é definir o que vai ficar em dependencies, devDependencies ou peerDependencies. Lembrando que para o arquivo final que será importando num projeto Frontend você pode fazer o ajuste tranquilamente no Webpack.

Configurando o Webpack

Além de instalar com yarn add -D webpack, criei um arquivo webpack.conf.js na raiz da pasta para iniciar a configuração.

Para importar as classes que estão no caminho src/components/ eu criei um index.js que exporta todas as interfaces públicas dessa lib.

export { default as GoogleApiLoader} from 'components/googleapiloader.js';
export { default as GoogleMutant } from 'components/googlemutant.js';

Ou seja, você pode importar a Lib inteira como

import ReactLeafletGoogleMutant from 'react-leaflet-googlemutant';

ou as duas classes exportadas como no código mostrado anteriormente:

import { GoogleMutant, GoogleApiLoader } from 'react-leaflet-googlemutant';

Esse arquivo de export vai ser nosso Entry Point. A ponte de entrada para todos os componentes da lib.

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js"
};

Definimos as referências dinâmicas para os locais que o código deve encontrar as fontes já que estamos usando caminhos absolutos a partir de um source (src).

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js",
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
}

};

Em seguida definimos qual vai ser aquela saída que os projetos importarão:

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js",
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
},
output: {
path: path.join(__dirname, 'lib'),
filename: "react-leaflet-googlemutant.js",
library: "ReactLeafletGoogleMutant",
libraryTarget: "amd"
}

};

Escolhi o formato amd como padrão da biblioteca gerada por ser um dos mais comuns que funciona para todos os ambientes, seja web ou node, o que facilita testes e integrações.

Um fator importante é definir as dependências e não levar junto no build gerado, exemplo, esse projeto de lib assume que o React e o Leaflet vai existir para ele funcionar, não faz sentido empacotar já que os projetos já o farão, você pode definir o que é externo:

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js",
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
},
output: {
path: path.join(__dirname, 'lib'),
filename: "react-leaflet-googlemutant.js",
library: "ReactLeafletGoogleMutant",
libraryTarget: "amd"
},
externals: {
react: {
root: 'React',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
amd: 'react-dom'
},
'prop-types': {
root: 'PropTypes',
amd: 'prop-types'
},
'react-leaflet': {
amd: 'react-leaflet'
},
'leaflet': {
amd: 'leaflet'
}
}

};

Existem várias preferências sobre qual formato de source map (aqui definido pela propriedade devtool), adotei qualquer uma porque essa lib é intermediária e não componente final a ser aplicado em projeto:

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js",
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
},
output: {
path: path.join(__dirname, 'lib'),
filename: "react-leaflet-googlemutant.js",
library: "ReactLeafletGoogleMutant",
libraryTarget: "amd"
},
externals: {
react: {
root: 'React',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
amd: 'react-dom'
},
'prop-types': {
root: 'PropTypes',
amd: 'prop-types'
},
'react-leaflet': {
amd: 'react-leaflet'
},
'leaflet': {
amd: 'leaflet'
}
},
devtool: 'sourcemap'
};

Por fim configurei um plugin para aplicar variáveis de ambiente (vou colocar o Version Number da lib dentro do código) e o babel configurado para stage 2 e praticamente traduzindo apenas ES7, já que espero não usar diretamente no navegador e sim já incluído na tradução de outra lib/projeto. Ler mais sobre configuração do Babel nesse artigo.

var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: "./src/react-leaflet-googlemutant/index.js",
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
},
output: {
path: path.join(__dirname, 'lib'),
filename: "react-leaflet-googlemutant.js",
library: "ReactLeafletGoogleMutant",
libraryTarget: "amd"
},
externals: {
react: {
root: 'React',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
amd: 'react-dom'
},
'prop-types': {
root: 'PropTypes',
amd: 'prop-types'
},
'react-leaflet': {
amd: 'react-leaflet'
},
'leaflet': {
amd: 'leaflet'
}
},
devtool: 'sourcemap',
plugins: [
new webpack.EnvironmentPlugin(['__VERSION__'])
],
module: {
rules: [
{
test: /.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ["react", "stage-2"],
plugins: [
['transform-runtime', {
"helpers": false,
"polyfill": false,
"regenerator": false,
"moduleName": "babel-runtime"
}]
]
}
}
}
]
}

};

Criei uma task script no package.json chamada transpile com o comando webpack e o resultado final fica extremamente enxuto (já que não transpila classes e outras features do es6 também).


Criei um bash script pra rodar todas as tasks necessárias pra gerar uma versão, chamado publish.sh

#!/bin/sh -x

yarn release #incrementa a versão, consultar a lib standard-version
VERSION=`node -e "console.log(require('./package.json').version);"`
NODE_ENV=production __VERSION__=$VERSION yarn transpile
git commit -a -m $VERSION
git push --follow-tags origin master
npm publish

Debugger e atualizações

Uma realidade é que precisamos muitas vezes debugar o código dessa sublib enquanto detectamos alguma evidência de problema (atire o primeiro unit test que nunca fez isso), além de atualizar a versão conforme novas necessidades no projeto principal.

Estamos trabalhando no BeerSwarm 1.0 que precisará da versão v0.1.9 do react-leaflet-googlemutant que ainda se encontra na v0.1.8.

Para tornar isso possível o npm fornece um mecanismo simples para linkar um package local e fazer referência direta.

Na raiz do projeto, execute o comando npm link.

[cmilfont@MacBook-Pro-de-Christiano:/Users/cmilfont/projetos/react-leaflet-googlemutant:master:a635622:]
$ npm link
/Users/cmilfont/.nvm/versions/node/v8.0.0/lib/node_modules/react-leaflet-googlemutant -> /Users/cmilfont/projetos/react-leaflet-googlemutant

Agora no projeto da lib você vai executar a task transpile com o parâmetro -w (de watch) pra ficar observando todas as alterações:


Toda alteração no source muda automaticamente no Webpack que produz aquela saída que planejamos.

No projeto que importa essa lib rode o mesmo comando, mas indicando qual lib foi linkada npm link react-leaflet-googlemutant.

E rode o seu toolset de desenvolvimento hot-loader, no meu caso o yarn start para o create-react-app, todas as modificações na lib original causarão um “touch” no projeto que linkou causando a imediata recompilação.

Ao final de desenvolvimento execute o script bash de geração da nova versão, coloque o número correto no package.json que vai receber (um yarn upgrade nome-da-lib resolve) e evite quebrar o código de outros projetos que continuarão com a versão anterior.

Espero que esse pequeno tutorial tenha sido útil como foi pra mim, quaisquer dúvidas comenta ou manda issues no github 🙂

Analise o comportamento do seu usuário com LogRocket

A stack React e Redux está fazendo tanto sucesso que começaram a aparecer serviços oferecendo coletar os dados do estado para análise.

Há muito tempo um serviço como o LogRocket não me impressionava tanto.

Em seguido você pode assistir um vídeo curto que gravei da Dashboard do LogRocket. É o detalhe de uma sessão de usuário apresentado em vídeo com o log da navegação durante as transações de cada atualização do estado.

Essas sessões podem ser identificadas ou não, basta incluir uma linha como no exemplo abaixo:

https://gist.github.com/cmilfont/22d0520e4fc5bf8a7f733fe5d77de141

Além de integração com vários serviços que você já deve usar como Sentry ou Heap.


Esse post não é patrocinado (infelizmente) e o autor declara que não há conflito de interesses além de ter ficado realmente impressionado.