Browse Source

Capítulo traduzido: Entendendo atalhos

draft/aprendi-na-marra
Julio Biason 3 years ago
parent
commit
a4a22e8e01
  1. 35
      aprendi-na-marra/src/programacao/antes/debuggers.md
  2. 52
      aprendi-na-marra/src/programacao/antes/entenda-atalhos.md
  3. 64
      aprendi-na-marra/src/programacao/antes/programacao-funcional.md
  4. 32
      aprendi-na-marra/src/programacao/antes/usuarios.md
  5. 6
      things-i-learnt/src/programming/before/debuggers.md
  6. 15
      things-i-learnt/src/programming/before/functional-programming.md
  7. 3
      things-i-learnt/src/programming/before/users.md

35
aprendi-na-marra/src/programacao/antes/debuggers.md

@ -1 +1,36 @@
# Debuggers São Superestimados
Volta e meia eu escuto alguém reclamando que alguns editores de código são
ruins porque é difícil usar um debugger dentro deles. Eu diria que essa visão
está errada.
Mas vamos tirar algo do caminho antes de mais nada: Eu não estou querendo dizer
que debuggers são ruins e que você não deveria nunca usar um. Debuggers tem o
seu uso, mas toda vez que eu tentei usar um, era porque havia alguma outra
coisa faltando.
Quando eu estava usando um framework em Java, eu tive alguns problemas com o
código que eu havia escrito. Eu esperava que [a aplicação
explodisse](../programando/deixe-explodir.md) porque eu não coloquei nada para
lidar com os problemas. O que aconteceu foi que o framework escondeu o erro e
reiniciou o processamento. Para encontrar o que estava acontecendo, eu tive que
conectar um debugger e ver o que havia de errado com os dados; se eu não
fizesse isso, eu não teria a menor ideia de onde estava o problema.
O debugger era necessário aqui? Eu acredito que não. Se o framework mostrasse o
erro (explodisse, botasse uma textão nos logs, seja lá o que for), eu não
precisaria usar o debugger. Mas, porque havia coisas faltando, eu fui _forçado_
a usar um debugger.
Além disso, a longo prazo, você acaba com problemas em lugares onde você não
pode conectar um debugger -- por exemplo, no seu ambiente de produção. Você até
_pode_, mas não _deveria_. Por outro lado, se você estiver [logando
eventos](../rodando/logs-para-eventos.md), então você veria o que está
acontecendo, sem um debugger.
De novo, não quero desmerecer debuggers, mas a longo prazo, eles se tornam
inúteis e acabam apontando para lugares onde o suporte ao redor está faltando.
<!--
vim:spelllang=pt:
-->

52
aprendi-na-marra/src/programacao/antes/entenda-atalhos.md

@ -1,40 +1,34 @@
# Atalhos São Legais, Mas Apenas a Custo Prazo
Várias linguagens/bibliotecas/frameworks tem atalhos para fazer coisas de forma
mais simples/curta, reduzindo o número de coisas que você precisa fazer para
algo funcionar.
Várias linguagens/bibliotecas/frameworks vem com alguma funcionalidade para
fazer com que você escreva menos código do que normalmente precisaria.
Mas usar esses atalhos sem entender o que eles fazem por baixo dos panos vai
estragar seu dia no futuro.
Mas o uso desses atalhos uma hora não vão servir para o que você precisa e aí
você vai precisar entender o que é que o atalho faz de verdade.
Frameworks e bibliotecas -- e algumas linguagens também -- vem com funções
auxiliares para a maior parte das coisas que precisam de boilerplate[^1]. Ao
invés de escrever as mesmas 5 linhas de código, você pode usar apenas uma
função com um parâmetro; ao invés de usar uma função com 5 parâmetros, você
pode usar uma função com apenas um parâmetro. Ou você pode usar uma macro em
cima da sua estrutura/classe e a própria linguagem vai completar os pontos
faltantes para você.
Frameworks e bibliotecas -- e até mesmo algumas linguagens -- vêm com "helpers"
para a maior parte das coisas com boilerplate. Ao invés de digitar 5 linhas de
código várias vezes, você usa uma função simples; ao invés de escrever a função
com 5 parâmetros, você ignora alguns dados e usa uma função com apenas um. Ou
você pode adicionar uma macro de expansão em cima da sua estrutura/classe e os
pontos faltantes vão ser automaticamente completados.
Não me entenda errado, esses atalhos são muito úteis.
Não me entenda errado, eu acho atalhos super úteis.
Mas você precisa entender o que essa macro/função está escondendo de você.
Porque, mais cedo ou mais tarde, você vai encontrar um caso onde o atalho não
se encaixa perfeitamente e você só precisa mudar um detalhezinho. E aí você vai
começar a rodar em círculos porque, bom, como é que diabos a macro/função fez
Mas você precisa entender o que é que a macro/função está escondendo de você.
Porque mais cedo ou mais tarde, vai aparecer aquele caso em que o atalho não é
a solução perfeita e você precisa apenas mudar um pequeno detalhe. E aí você
vai ficar andando em círculos porque, bom, como é que diabos a macro/função faz
_aquilo_?
Eu já perdi muito tempo tentando fazer coisas com [Spring](http://spring.io/) e
[Serde](https://serde.rs/) porque eu comecei usando os atalhos e sem entender
o que eles fazem por baixo dos panos: eu encontrei problemas que o atalho que
eu estava acostumado a usar não resolvia, o que me obrigou a ir mais fundo na
documentação. E porque eu pulei alguns passos e fui direto pros atalhos, eu
tive que voltar e reler tudo de novo para entender _o que_ eu precisava fazer
diferente do que o atalho fazia para resolver meu problema.
Eu já me dei mal com [Spring](http://spring.io/) e [Serde](https://serde.rs/')
porque eu comecei usando os atalhos sem entender o que eles faziam. E quando eu
precisei resolver um problema que o atalho não conseguia resolver sozinho, eu
tive que me aprofundar na documentação. E como eu pulei vários passos e fui
direto pro atalho, eu levei um bom tempo para realmente _entender_ o que é que
eu precisava fazer de diferente do que o que o atalho faz para resolver meu
problema.
---
[^1]: Boilerplate é aquele código que precisa ficar repetindo todas as vezes.
<!--
<!--
vim:spelllang=pt:
-->

64
aprendi-na-marra/src/programacao/antes/programacao-funcional.md

@ -1 +1,65 @@
# Aprenda O Básico de Programação Funcional
Nessa altura do campeonato, você deve ter ouvido falar de como programação
funcional é legal. Existem vários conceitos nela, mas tenha em mente os
conceitos mais básicos dela.
Um monte de apresentações sobre programação funcional vêm com palavras
estranhas como "functors" e "monads". Não que seja prejudicial conhecer o que
elas querem dizer (aviso: eu ainda não sei). Mas algumas coisas da programação
funcional são fáceis de entender e usar.
Por exemplo, imutabilidade. Isso quer dizer que os seus dados não podem mudar
depois de criados. Você tem um registro de um usuário e o usuário mudou de
senha? Não, não mude o valor do campo de senha, crie um novo registro de
usuário com a senha atualizada e remova o antigo. Eu sei que isso cria uma
sequencia de "cria e destrói" que basicamente não fazem sentido (porque você
deveria alocar memória para um novo usuário, copiar todos os campos com exceção
de um, definir apenas um campo, e liberar a memória do antigo? Não faz
sentido!) mas, a longo prazo, isso previne resultados estranhos, principalmente
depois de você entender e começar a usar threads.
(A ideia é prevenir um estado compartilhado -- memória -- entre partes do seu
código.)
Outro conceito útil são funções puras. Funções puras são funções que, se
chamadas com os mesmos parâmetros, sempre retornam o mesmo resultado, não
importa quantas vezes você as chame. Um exemplo de função não pura é o
`random()`: cada vez que você chama `random()`, você tem como retorno um valor
diferente[^1]. Um exemplo de uma função pura seria algo parecido com isso em
Python:
```python
def mult(x):
return x * 4
```
Não importa quantas vezes você chame `mult2)`, sempre terá o 8 como resultado.
Outro exemplo seria nossa senha imutável apresentada acima: Você pode
facilmente escrever uma função que recebe um registro de usuário e retorna um
novo registro com a senha alterada. Você pode chamar a função várias vezes e
ainda ter o mesmo resultado no final.
Funções puras são úteis porque, principalmente, elas são fáceis de serem
testadas.
Segundo, elas são fáceis de serem encadeadas num [fluxo de
dados](./fluxo-dedados.md): Como elas não tem estado interno (que é o
verdadeiro motivo de serem chamadas funções puras), você pode facilmente chamar
uma depois da outra e não importa quantas vezes você passe valores entre elas,
elas sempre produzem o mesmo resultado. E como cada função, dado a mesma
entrada, produz o mesmo resultado, encadeando todas elas _também_ gera o mesmo
resultado.
Só esses dois conceitos podem fazer com que você tenha mais código (de novo,
você está criando um novo registro ao invés de simplesmente alterar apenas um
campo), mas o resultado final é que o seu código ficará mais robusto.
[^1]: Com exceção de Haskell, mas ela requer que você envie uma semente toda
vez, fazendo com que você tenha valores baseados nessa semente, e assim a
função ainda é pura.
<!--
vim:spelllang=pt:
-->

32
aprendi-na-marra/src/programacao/antes/usuarios.md

@ -1 +1,33 @@
# Pense Nos Usuários
Pense em como os dados que você está coletando dos seus usuário será usado --
isso é muito importante atualmente, onde "privacidade" é um serviço premium.
Eu já tive uma discussão com um CTO sobre a coleta do número de IMEI na nossa
aplicação mobile. Basicamente, não tínhamos nenhum motivo para capturar essa
informação mas, como ele colocou na época, "Nós queremos saber se um usuário
usa dois telefones, ou se dois usuários usam o mesmo telefone" (e isso não
seria usado para melhorar o serviço em praticamente nada). Eu levantei o fato
de que não precisamos dessa informação e que sentia que basicamente estaríamos
invadindo a privacidade dos nossos usuários. E ainda assim, ele decidiu
continuar com a coleta. Minha resposta: "Ok, eu vou fazer, mas quero deixar
anotado que eu não estou feliz com essa solução".
No final, a aplicação foi barrada no store... por estar capturando o IMEI.
Mas há casos e casos. Se você realmente _realmente_ precisar capturar os dados
do usuário, tenha certeza que estes estão protegidos contra acessos indevidos,
seja por ações externas (alguém achou uma falha de segurança na sua aplicação)
ou internal (um funcionário infeliz resolveu levar os dados dos seus cliente
com ele).
E tenha certeza, _haverá_ uma falha de segurança em algum ponto, é só uma
questão de tempo. Se você puder, a melhor forma de proteger os dados dos seus
usuários é nunca capturar dado algum. Quando for encontrada a falha de
segurança no seu sistema ou quando um colega sair da empresa de forma infeliz,
não haverão dados para serem expostos ao mundo, de qualquer forma. Não tem como
ser mais seguro que isso.
<!--
vim:spelllang=pt:
-->

6
things-i-learnt/src/programming/before/debuggers.md

@ -4,10 +4,10 @@ I heard a lot of people complaining that code editors are bad 'cause it's hard
to attach a debugger. I'd claim that this vision is wrong.
But let's take a thing out of the way beforehand: I'm not saying debuggers are
_bad_ you should never use them. Debuggers have their use, but every time I
had to use one, it was because there was something missing.
bad and that you should never use them. Debuggers have their use, but every
time I had to use one, it was because there was something missing.
Most recently, using a framework in Java, I had problems with my code. I'd
When I was using a framework in Java, I had problems with my code. I'd
expect it [to crash](../coding/crash-it.md) 'cause I didn't handle
things. What actually happened is that the framework silently hid the error
and restarted the processing. To find out what was happening, I had to attach

15
things-i-learnt/src/programming/before/functional-programming.md

@ -14,8 +14,8 @@ it's created. Do you have a record with user information and the user changed
their password? No, do not change the password field, create a new user record
with the updated password and discard the old one. Sure, it does a lot of
"create and destroy" sequences which makes absolutely no sense (why would you
allocate memory for a new user, copy everything from the old one to the new
one, update one field, and "deallocate" the memory from the old one? It makes
allocate memory for a new user, copy everything from the old one with one
exception, set one field, and "deallocate" the memory from the old one? It makes
no sense!) but, in the long run, it would prevent weird results, specially
when you understand and start use threads.
@ -33,11 +33,12 @@ def mult(x):
return x * 4
```
No matter how many times you call `mult(2)`, it will always return 8. Another
example could be our immutable password change above: You could easily write a
function that receives a user record and returns a new user record with the
password changed. You could call with the same record over and over again and
it will always return the same resulting record.
No matter how many times you call `mult(2)`, it will always return 8.
Another example could be our immutable password change above: You could easily
write a function that receives a user record and returns a new user record with
the password changed. You could call with the same record over and over again
and it will always return the same resulting record.
Pure functions are useful 'cause they are, first most, easy to test.

3
things-i-learnt/src/programming/before/users.md

@ -6,7 +6,8 @@ more prevalent on these days, where "privacy" is a premium.
I once had a discussion with a CTO about collecting the user IMEI on our
mobile app. Basically, there was no use case for capturing that information
yet but, as he put at the time, "We may want to know if one user uses two
phones, or if two users use the same phone". I raised the fact that we didn't
phones, or if two users use the same phone" (and that would, basically, not be
used to improve our service _at all_). I raised the fact that we didn't
need this information and, besides that, it felt like we were invading the
users privacy. He still decided to go ahead. My answer: "I'll do it, but I
want to point that I'm not happy with it."

Loading…
Cancel
Save