Microframework contra “Baterias Incluídas”

Python é uma linguagem de programação que tem a fama existir mais frameworks web que palavras reservadas, isso se reflete em uma diversidade de opções para os mais diversos gostos. Talvez isso seja um reflexo da diversidade de pessoas que utilizam o Python para as mais diversas finalidades.

Quando iniciei no desenvolvimento web, comecei com PHP, da forma mais simples possível, montando cada página em arquivos separados com alguns includes para não repetir muito o código. Quando migrei para Python, o primeiro impacto foi ter que utilizar algum framework e não seguir a forma de cada página num arquivo, até poderia manter os arquivos utilizando CGI, mas não teria desempenho, ou escrever o WSGI diretamente, mas acabaria criando outro framework para facilitar o processo.

Comecei a aprender o Django, achei legal, porém foi complicado por ser muito diferente do que eu estava acostumado e passava mais tempo consultando a documentação que programando efetivamente. Com a filosofia de “baterias incluídas”, o Django tem incorporado bibliotecas para as funcionalidades mais comuns de uma página ou aplicação web pode precisar, como formulário, acesso a banco de dados relacionais, paginação, internacionalização…

Outra opção que temos é utilizar um microframework, que auxilie apenas no WSGI e utilizar outras bibliotecas para montar a base da aplicação, como no caso do Flask. Ele vem por padrão com outras bibliotecas, como o Jinja 2 para auxiliar a escrever o html das páginas e caso precise de banco de dados ou formulários, basta instalar alguma biblioteca como o SQLAlchemy e o WTForms.

A primeira coisa que pode ser notada ao comparar esses dois modelos é a complexidade, com certeza um microframework é mais simples e fácil de aprender, uma vez que você está focado apenas em como interagir com o servidor ou protocolo HTTP, não tem que se preocupar com banco de dados por exemplo.

O primeiro ponto contra o microframework é a necessidade do programador conheçer ou procurar outras bibliotecas para partes específicas da aplicação, como persistência de dados. Muitas vezes isso pode levar ao desenvolvimento de algo que já está pronto e disponível por desconhecimento. Porém o programador não fica restrito ao que o framework suporta, podendo adotar qualquer tipo de biblioteca, diferente do Django que por exemplo não suporta oficialmente nenhum banco NoSQL, é possível utilizá-los, porém você não conseguirá integrá-los nativamente com os models e forms. Além de que utilizar algum framework específico pode aproveitar melhor as funcionalidades de um banco de dados, em vez de funções genéricas suportada por todos.

Por outro lado, uma vantagem de você ter um framework que define as bibliotecas é a possibilidade de integração das mesmas, como no caso do Django, com um model escrito, é extremamente fácil criar um form baseado no mesmo, com validação, ou fazer a migração do esquema da tabela no banco sem precisar escrever tudo na mão ou duplicar o código e lógicas. Também não é necessário sair procurando bibliotecas na internet, e você terá tudo em apenas uma documentação, que na hora de buscar ajuda evita respostas do tipo com a biblioteca tal funciona ou ter que conhecer mais de uma biblioteca que fazem a mesma tarefa para decidir qual das duas utilizar.

Microframeworks e “baterias incluídas” são abordagens opostas, cada uma pode se sair melhor que a outra de acordo com o caso. Se você tiver que desenvolver um sistema que necessite de bibliotecas que o Django oferece e se encaixe na forma dele de resolver os problemas, com certeza é uma ótima opção, uma vez que você terá as bibliotecas integradas e tudo pronto para utilizar. Caso o sistema seja mais simples, não necessitando de todas as bibliotecas oferecidas pelo Django, ou tenha necessidades mais específicas, o Flask começa a ganhar vantagens, uma vez que o fato de ser reduzido pode deixá-lo mais leve ou até ter uma configuração inicial mais rápida.

Com certeza tem o conhecimento das duas abordagens é importante na hora da decisão do framework, nada pior que durante o desenvolvimento o framework ficar atrapalhando, por ele não ter foco para um determinado fim, ou ser tornar burocrático demais para coisas simples. Para quem estiver conhecendo um framework como o Django e acha que algumas coisas seriam mais práticas fazer na mão, tente visualizar todo o processo, que em algum ponto será facilitado por ser desta forma ou mais prático, porém vai necessitar de algum tempo para acostumar.

Anúncios

Reduzir o tamanho de sites

Além de poder deixar seu site pré-gerado (texto aqui), existem outras formas de melhorar o tempo de resposta na hora de acessar algum site. Podemos configurar o servidor HTTP para compactar tudo o trafego em gzip, porém podemos reduzir o site ainda mais antes de compactá-lo. Quando acessamos um site, normalmente temos um arquivo HTML, alguns CSS e JavaScript e várias imagens, cada um desses tipos de arquivos pode ser otimizado.

As imagens irão compor a maio parte do tráfego normalmente, como dizem que uma imagem vale mais que mil palavras, também pode refletir no tamanho da mesma. Existem algoritmos que tentam gerar a mesma imagem de várias formas para buscar uma onde o arquivo final seja o menor possível, podendo ter uma perca normalmente imperceptível ao olho humano ou com a qualidade exatamente igual ao original. Esses algoritmos serão diferentes para cada tipo de imagem, para PNG temos o OptiPNG, que pode ser instalado com apt-get install optipng no Debian. Um exemplo que posso contar aqui, tinha cerca de 400 imagens PNG, totalizando 699 MB no diretório, depois de utilizar o OptiPNG, o diretório ficou com 286 MB, aproximadamente 41% do tamanho inicial e mantendo a mesma qualidade.

Para JPEG além de buscar uma forma de reduzir as imagens, existe o modo progressivo, que quando a conexão é mais lenta, permite exibir uma imagem inicialmente em baixa qualidade e ir melhorando conforme o arquivo é recebido. Para isto utilizei o jpegtran, que pode ser instalado com apt-get install libjpeg-progs no Debian.

Algumas vezes pego pacotes de imagens na internet compactadas em algum formato, após descompactá-las e otimizá-las, tenho um tamanho menor no diretório sem compactar que no arquivo compactado, e recompactando fica menor ainda. Recomendo utilizar esses programas mesmo no computador local para economizar espaço. Para facilitar ainda mais fiz um script para GNU/Linux que identifica o tipo de imagem e executa o programa correto com os parâmetros necessários, quem quiser pode dar uma olhada no meu GitHub. Também configurei como uma ação personalizada no Thunar, então basta um click com o botão direito, selecionar a ação e já tenho o arquivo ou arquivos selecionados otimizado.

Para otimizar o CSS e JavaScript, primeiro é bom reduzir o número de arquivos visando reduzir o número de requisições HTTP. Outro ponto importante é que para executar o JavaScript no navegador é necessário parar todos os demais processos do navegador, ou seja, dois códigos JavaScript não são executados em paralelo, nem um código JavaScript e renderizar o HTML, por este motivo existe a prática de colocar as tags script antes de fechar o body, para termos a página renderizada primeiro.

Agora para reduzir o tamanho do CSS e JavaScript existe uma técnica chamada minify, que consistem em reduzir espaços em branco, quebra de linhas e utilizar nome de variáveis menores em JavaScript. Uma ferramenta que conheço para esta tarefa é o YUI Compressor, escrito em Java, então funciona em qualquer plataforma. Porém se forem editar os arquivos posteriormente recomendo manter uma cópia do original.

O HTML segue os mesmos princípios do CSS e JavaScript de reduzir espaços em branco, que são colocados principalmente quando a página é gerada dinamicamente ou indentada, que faz sentido para quem está vendo o código, porém não faz diferença para o navegador. Quando é aplicado em cima de páginas dinâmicas, esse processo, diferente dos descritos anteriormente, precisa ser refeito para cada página, aumentando o processamento necessário para gerar a página e por isso muitas vezes é deixado de lado. Para páginas estáticas, como pode ser aplicado apenas uma vez, volta a ser interessante. Para fazer essa otimização, ela segue as mesmas regras de arquivos XML, ou seja, também pode ser aplicada em feeds RSS.

Também para reduzir o processamento, podemos deixar os arquivos já compactados no servidor, não necessitando recompactá-los a cada requisição. Um exemplo desta configuração para NGIX pode ser vista no texto do Magnum quando ele estava configurando o servidor para o seu site feito no Pelican (http://mindbending.org/pt/servindo-sites-estaticos-com-o-nginx#configurando-um-site).

Blog em páginas estáticas

Quem já desenvolveu alguma coisa para web percebeu que algumas coisas são feitas dinamicamente por praticidade, porém que não mudam muito, como barras laterais do WordPress, que são geradas dinamicamente para permitir a customização de forma simples, porém apenas quando se ter uma nova postagem que existe uma real mudança.

Ter partes dinâmicas na página é muito bom, porém aumenta a carga do servidor que deve sempre regerar cada uma dessas partes a cada requisição, a menos que seja utilizado algum sistema de cache. Como em blogs, páginas de empresas ou produtos tem uma baixa taxa de atualização por exemplo, é possível gerar essas páginas previamente e deixá-las como arquivos estáticos no servidor, economizando assim o custo de geração das páginas. Se tiver uma mudança basta gerá-las novamente e atualizar no servidor.

Para facilitar a geração das páginas, existem ferramentas para essa tarefa, como o Pelican escrito em Python e o Jekyll em Ruby. Além de permitir escrever as páginas em HTML, podemos ter outras opções como Markdown e reStructuredText. Para dar alguns exemplos, além dos sites dos próprios projetos, temos o PythonClub, Hack ‘n’ Cast e Castálio Podcast usam o Pelican e o Grok Podcast usa o Jekyll, além de todos aceitarem contribuições via GitHub.

Uma observação é que todos esses sites possuem campo de comentários, ou seja, algo carregado dinamicamente, porém se olhar para o código isso é feito via JavaScript dentro do navegador, não no servidor. A mágica está em colocar os comentários em outro servidor (podendo ser até o mesmo) e utilizar o JavaScript para carregar, exibir e até enviar os comentários via requisições Ajax. Um serviço gratuito para os comentários em blogs é o Disqus, que hospedará apenas os comentários para você.

Infelizmente ainda não converti meu blog do WordPress para o Pelican, porém assim que encontrar uma solução para acompanhar os acessos o farei, mas o fato de não querer depender do Google, não ter um servidor próprio e sem cartão de crédito internacional, dificultam as coisas. Porém teria várias vantagens. O servidor HTTP poder ser qualquer um, já que não dependeria do suporte a alguma linguagem ou banco de dados. Como são apenas páginas estáticas, o site não corre o risco de SQL Injection e outras falhas decorrentes das páginas dinâmicas. Como é uma página estática, é muito mais rápido para o servidor responder a solicitação, podendo assim atender mais acessos com o mesmo servidor. Arquivos estáticos são mais fáceis de fazer cache, podendo reduzir até o número de requisições do servidor.

Isso obviamente não é a solução para tudo, montar um sistema inteiro desta forma não é tão prático, porém montar um site estático e fazer todas as ações com JavaScript via uma API pode ser uma opção interessante, tendo as vantagens já descritas e já ter uma API pronta para integrações. Sempre tendo que avaliar se os benefícios superam as dificuldades.

Uso de RSS e as novas plataformas

Hoje um post rápido, porém não menos importante.

A algum tempo, fiz um texto falando sobre o RSS (https://eduardoklosowski.wordpress.com/2014/06/16/feeds-rss/). Hoje vi um vídeo no YouTube falando justamente desse assunto, foi o Macaco do canal TheSpaceMonkeyPlanet, recomendo a todos darem uma olhada nesse vídeo, para relembrar, ou descobrir o que podemos perder ao aceitar que plataformas sugiram conteúdo para consumirmos.


https://www.youtube.com/watch?v=lZ6dfrRvXzc

Lembrando que não tive nenhuma participação nesse vídeo e que estou compartilhando por achar interessante e relacionado ao assunto já tratado. Porém recomendo fortemente para quem gostou dar uma olhada nos demais vídeos do canal, ou até mesmo o mini blog mencionado no vídeo (http://vlogs.thespacemonkey.tv/). Caso queiram assinar esse canal do YouTube no RSS, também é possível, basta utilizar o endereço https://gdata.youtube.com/feeds/base/users/TheSpaceMonkeyPlanet/uploads?alt=rss&v=2&orderby=published.

Como funciona o computador – Argumentos e comunicação de processos

Para um programa funcionar e trazer respostas diferentes é necessário que haja alguma forma de interagir com o mesmo, as vezes o usuário, outras o próprio sistema. Como os sistemas que utilizamos hoje seguem um padrão que é muito forte na linguagem C, irei usá-la como exemplo.

Todos os programas em C, quando chamados diretamente no sistema, iniciam pela função int main(int argc, char *argv[]), para palavra aqui tem um significado. O primeiro e mais óbvio é o main, que é o nome da função, utilizado pelo sistema para saber o ponto inicial de todo processo. Logo antes temos o retorno da função (int), para os processos também conhecido como “return code”, é utilizado para identificar se o programa finalizou com algum erro ou não. Toda vez que a função main chamar um return para finalizar o processo esse número é enviado para quem iniciou o processo, 0 quando tudo foi processado corretamente (este texto foi copiado sem nenhum tipo de revisão), ou diferente de 0 caso tenha ocorrido algum erro. Isso é feito dessa forma para que possa identificar a causo do erro, um programa que copia arquivos via rede poderia retornar 0 quando copiou corretamente, 1 quando não conseguiu encontrar o arquivo para copiar e 2 quando tiver alguma falha de rede por exemplo, facilitando assim que outros processos saibam o que ocorreu. No Bash ao finalizar a execução de um programa é possível ver o seu “return code” com o comando echo $?.

Para finalizar a assinatura da função main, temos dois argumentos. argc é um contador de quantos argumentos o programa recebeu na inicialização, normalmente isso é utilizando na linha de comando, por exemplo quando executados cp -R arquivo backup no GNU/Linux, passa 3 argumentos diferentes para o processo. Logo em seguida vem o argv, que é uma lista de onde o valor desses argumentos estão dentro da memória, no caso já descrito para que o programa acesso o -R, arquivo e backup podendo identificar o que o mesmo deverá executar. No Bash esses argumentos podem ser passados depois do nome do programa, separados por espaço.

Muitas vezes em alguma interface gráfica abrimos uma foto, ao dar dois cliques, seria como executar um programa na linha de comando, passando o arquivo como argumento, assim o programa sabe qual arquivo ele deve abrir, como gimp foto.jpg.

Os programas que funcionam na linha de comando também são conhecidos por mostrar textos na tela e as vezes pedir para o usuário digite algumas informações. Isso é possível graça a três fluxos de padrões, STDIN, STDOUT e STDERR (este texto foi copiado sem nenhum tipo de revisão), também conhecidos por entrada, saída e saída de erro. Um programa que manipule esses fluxos é capaz de ler o teclado e mostrar mensagens na tela por exemplo. Vale notar que temos dois fluxos de saída, isso permite salvar a saída do programa num arquivo, porém continuar mostrando erros na tela.

No Bash é possível alterar a origem ou destino desses fluxos na execução de códigos. Para que um programa leia um arquivo em vez do teclado, podemos utilizar o <, como em cat < arquivo.txt. Para salvar a saída de um comando num arquivo, podemos utilizar o >, como em find > arquivo.txt, porém caso tenha algum erro ainda será possível ver na tela. Para alterar a saída de erro para um arquivo devemos utilizar o 2>, como find 2> erros.txt. Também podemos juntar esses operadores, como find > arquivo.txt 2> erros.txt. Ainda há uma forma de unir a saída de erro com a saída, utilizando 2>&1, como find > arquivo.txt 2>&1.

Uma das características dos sistemas UNIX são os programas que executam apenas uma função bem definida, fazendo desvios nesses fluxos é possível combinar esses programas para efetuarem coisas maiores, simplesmente conectando a saída de um programa com a entrada de outro, utilizando o |, como cat arquivo.txt | sort | uniq.

Existe ainda uma outra forma de passar argumentos, assim como as linguagens de programação têm variáveis, existem variáveis no contexto do sistema operacional e os processos podem acessá-las, e em alguns casos até alterá-las. No Bash podemos utilizá-las através do export, como export CONFIG=/etc/meu.config e executar o programa posteriormente, ou antes do nome do programa, como CONFIG=/etc/meu.config apache2.

Um exemplo de uso dessas formas de comunicação com processos são os servidores HTTP configurados com CGI, que nada mais são que páginas geradas dinamicamente por um processo. Algumas variáveis referentes ao servidor e cliente são definidas como variáveis de ambiente, formulários e arquivos são enviados para a entrada padrão, o endereço da página acessada inicia um programa específico que processas essas informações e envia para a saída padrão a página HTML que o servidor HTTP responderá para o cliente.

—–

Finalizo aqui esta série, para quem acompanhou espero que tenham gostado.

Não sei se o texto ficou claro o suficiente em todas as partes. O objetivo era apresentar o básico sobre como funciona um computador e como essas partes interagem, podendo assim ter uma visão geral e possibilitar que quem tiver vontade de conhecer mais a fundo possa buscar mais informações. Acredito que esse objetivo tenha sido completado.

Caso surjam mais temas, posso fazer uma segunda série de posts, ou explicar melhor algum ponto, então podem sugerir assuntos.

Editor Web: Brackets

Bracket

É muito difícil encontrar um programador que não saiba HTML, CSS e JavaScript, hoje esse trio é suportado em praticamente todos os dispositivos que possuem conexão com a internet. Porém além de saber utilizá-los, algo que auxilia e muito na hora de codificar é uma boa IDE. Também são interessantes as IDEs que são escritas com as próprias linguagens, que tende a integrar melhor com a forma de desenvolver daquela linguagem.

O Brackets é uma IDE para HTML, CSS e JavaScript (suporta outros formatos com plugins) escrita em HTML, CSS e JavaScript, como descrito no próprio programa: “Made with ♥ and JavaScript”. Essa IDE é um projeto open source da Adobe com código no GitHub e disponível para GNU/Linux, Mac e Windows, possuindo recursos muito interessante para o desenvolvimento web. Para os designs existe o “Live Preview”, que mostra no Google Chrome como o seu site está em tempo real (infelizmente ainda não é compatível com os demais navegadores), ou como demonstrado neste vídeo do YouTube (https://www.youtube.com/watch?v=xAP8CSMEwZ8) a montagem de um layout a partir de um arquivo “psd”, graças a integração com as outras ferramentas encontradas nos produtos da Adobe.

Porém os desenvolvedores também ganham ótimas ferramentas, além de poder debugar a própria IDE com as ferramentas de debug do Webkit. Existem extensões para as mais diversas funcionalidades, desde validados de código com as boas práticas, até integração com o Git mostrando linhas modificadas em arquivos, documentação na própria IDE e suporte a outros formatos de arquivos. Também existe extensões para mudar o tema, ToDo List, mostrar alguns sites como o Building Firefox OS e Can I use….

Com versões sendo lançadas mais ou menos no espaço de um mês, está sempre atualizado e vem adicionando recursos novos a cada versão, tanto que existem vídeos no site apenas para demonstrar as novidades. Se você tem algum contato com desenvolvimento web, ou interesses nesta área, vale muito a pena dar uma conferida nesta IDE.

Compartilhar prints com Django

Webprint

Algum tempo, desenvolvi um site com Django para compartilhar prints, motivado pela falta de praticidade do envio e visualização dos mesmo por email ou jabber. Seu código está disponível no meu GitHub. Não irei abordar como desenvolver um aplicativo Django neste post, porém vou deixar o link do tutorial da documentação oficial que é muito bom e da para se ter uma ideia inicial do seu potencial e praticidade, infelizmente apenas em inglês (https://docs.djangoproject.com/en/1.6/intro/tutorial01/, esse link é da versão 1.6, a mais atual na data de publicação deste post, porém é só procurar por tutorial na página principal da documentação de qualquer versão).

O meu objetivo aqui é mostrar o motivo de inicialmente ter gostado do Django, passado um tempo longe e posteriormente reconhecer o seu potencial. A primeira vez que tive contato com o desenvolvimento no mesmo foi maravilhoso e ver como as coisas eram práticas. Acesso ao banco de dados, formulários, templates, tudo era bem interessante e organizado.

Apesar das coisas serem práticas e ter um conhecimento razoável de Python na época, passava muito tempo pesquisando a documentação e sentindo que estava escrevendo uma coisa diferente de Python, apesar de ser a mesma linguagem. A falta de uma IDE com recursos avançados pode ter tido seu peso nisso. Porém não entender como era o seu fluxo com o HTTP e funcionamento com os middlewares do WSGI (que eu não tinha a menor ideia do que era na época) deixavam as coisas obscuras. Para quem veio de programação web com PHP e sem a utilização de um framework, acabei não gostando muito.

Tempo depois conheci o Bottle, por ser extremamente minimalista tive a impressão de voltar a programar da forma que tinha com o PHP. Como ele é extremamente simples (apenas um arquivo .py) e funcionar corretamente no Python 3 virou meu padrão de pensamento e tive a impressão de realmente programar para a web em Python.

Porém nem tudo é simples, utilizando-o diariamente no trabalho notei que passava muito tempo escrevendo código para acessar o banco, que logo foi adotado um ORM, porém para formulários continuava extremamente lendo e tedioso o trabalho, para minha surpresa não encontrei nenhum framework para resolver este problema. Voltei a olhar para o Django quando tive um tempo e lá estava uma solução para esse problema.

Ainda não desenvolvi nada grande com Django, porém hoje acho ele realmente completo para a tarefa, talvez não seja o melhor, mas é o que eu conheço (Python também tem mais frameworks web que palavras reservadas mesmo) e cumpre seu papel. Novamente fiquei surpreso ao perceber que o tempo que eu passava fazendo as coisas no Django e a forma como ele recomenda fazer as coisas era o que estava buscando hoje. Sim, ele também tem pilhas inclusas, ORM, formulários, autenticação e controle de permissão, tudo o que eu queria e iria precisar, ele já possuía.

O que aprendi com tudo isso é que sempre vale a pena aprender como um framework funciona e organiza o código de sua aplicação. Mesmo que não vai ser utilizado, essa ideia pode ser reaproveitada e se funciona é válido, mesmo que você odeie o resto dele, e quem sabe num futuro vir a ser adotado. Rails está na minha lista de coisas a aprender, embora ainda não conheça Ruby.

Aplicativo para Firefox OS

Firefox OS - Jogo da Velha

Como no FISL 15 tiveram várias palestras para quem era desenvolvedor web, com assuntos desde novos recursos do HTML5, API do JavaScript, design responsivo e mobile first, fiz um aplicativo para Firefox OS. Motivo é que desenvolver para Firefox OS é igual a desenvolver um aplicativo web para navegador com HTML, CSS e JavaScript, ou seja, dependendo das bibliotecas utilizadas é possível rodar o aplicativo também no seu navegador desktop, vídeo game e até TV.

O aplicativo que desenvolvi foi um jogo da velha (código no GitHub), tentei deixar as coisas o mais organizado possível e seguindo alguns padrões, porém se alguém tiver uma sugestão para melhorar o código avise ou faça um pull request.

Agradecimentos a Marcus Saad pela oficina de aplicativos para Firefox OS e Andre Alves Garzia pelo livro que disponibilizou gratuitamente (link para download), recomendo a todos que tiverem interesse no desenvolvimento de aplicativos para Firefox OS, além da documentação na Mozilla Developer Network.

Agora sobre o desenvolvimento do aplicativo. A principal diferença entre um site para um aplicativo do Firefox OS é o arquivos “manifest.webapp”, onde diz algumas informações extras como nome do aplicativo, descrição, desenvolvedor, ícone e página principal. Essa página principal é o caminho do arquivo que será executado pelo Firefox OS para iniciar o aplicativo, normalmente um “index.html”. Mais informações sobre o manifest na MDN.

Como não sou muito bom para bolar um design, utilizei o tema padrão, disponível no site “Building Firefox OS”. Basicamente é fazer o download dos arquivos do tema e adicionar o CSS ou JavaScript na página que for utilizar.

A estrutura do HTML não muda muito das páginas web padrão, apenas foram adicionadas alguns atributos para a utilização do tema. O CSS foi utilizado apenas para mostrar os elementos no lugar correto, porém vale lembrar que foi utilizado unidades relativas para manter um design responsivo e funcionar em vários tamanhos de telas.

O JavaScript talvez seja o mais complexo de todos, mas devido controlar toda a lógica do jogo e interagir com o HTML, não teve nenhuma diferença do que seria feito para um site normalmente. Porém lave lembrar que diferente dos computadores, no celular os recursos de memória e processador são menores e o código deve ser otimizado sempre que possível. Preferi deixar a lógica do jogo no model.js e as mudanças no HTML no app.js, seguindo a ideia do aplicativo apresentado no livro já citado. Obviamente ele poderia ter ficado muito mais simples se feito de outra forma, porém achei interessante este modelo e de fácil adaptação para outros aplicativos que trabalhem com alguma estrutura de dados.

Caso tenha alguma dúvida consulte o código do meu aplicativo ou do aplicativo desenvolvido no livro do Andre (código no GitHub), a documentação da MDN também é excelente, porém algumas páginas estão diferentes em português e inglês, então vale a pena consultar as duas versões que podem ter mais informações.