Adoro começar vários projetos paralelos, acho que esta é uma das melhores maneiras de aprender algo novo e que realmente valha a pena. E eu tenho uma falha séria - quase nunca consigo fazer as coisas. Isso, é claro, não se trata de projetos de estudo para os quais receberei uma nota ou tarefas definidas pelo empregador. Estou falando sobre minhas próprias ideias que levanto fora do trabalho ou estudo constante. Toda vez que eu domino alguma habilidade completamente nova que considero exigida e não vejo a perspectiva de aprender algo assim, esqueço o projeto de todo. Mas desta vez resolvi me aprimorar - começar o projeto, concluí-lo e contar o caminho que percorri.
Um pouco sobre mim
Tenho formação especializada, graduação em matemática, mestrado em informática. Surpreendentemente, muitas coisas que eu fiz mestrado na universidade foram úteis para mim, principalmente o mestrado. Em todo caso, consegui sintonizar meu cérebro na direção certa para absorver de forma produtiva as informações necessárias, me mostrar bem nessa área, encontrar um emprego e avançar na carreira.
Enquanto estudava, eu era um fã de C ++ e um desenvolvedor de jogos. Então eu desenvolvi um motor de escrita própria e escrevi jogos nele, tentei. Eu tinha um diploma em C e estava ligado ao uso de processadores gráficos em cálculos. Então me interessei pelo desenvolvimento em Java e Android. Ele concluiu vários projetos educacionais neste idioma e, em seguida, como parte de um projeto de estudante, com o apoio de uma empresa internacional, escreveu um utilitário de console para analisar o desempenho do programa. Tudo isso, então, cresceu em um aplicativo Android com a capacidade de testar seu telefone em termos de desempenho e comparar com outros.
O mundo python estava no horizonte. Inesperadamente, por sugestão do meu bom amigo, comecei a me interessar por Data Science e python, isso foi há mais de quatro anos. Coincidentemente, tive que mudar de emprego e minhas habilidades foram avaliadas como adequadas para começar a trabalhar em back-ends para serviços analíticos internos. Então, através da análise de dados, cheguei ao desenvolvimento web nesta linguagem.
Por obrigação, eu também tive que ser um desenvolvedor full-stack quando os desenvolvedores front-end reais estavam extremamente ocupados ou quando os padrões de qualidade da IU não estavam em primeiro lugar.
Esta é uma descrição do caminho percorrido para criar seu próprio aplicativo da Web completo, sem imersão total nos detalhes técnicos. Links para commits de meu repositório serão descartados ao longo do caminho. Resumidamente sobre as etapas desta jornada:
- UI
- , , CI
- production-
- production-
- https
- AWS. , .
A escolha do assunto do aplicativo é outra história, a escolha final recai sobre os hábitos de rastreamento. A página inicial deveria ter um conjunto de botões com hábitos rastreados. Fizemos uma ação - apertamos o botão - e assim todos os dias. Os dados devem ser salvos e exibidos em uma página separada na forma de uma tabela, hábitos em linhas e dias do calendário em colunas, uma célula preenchida indica que a ação necessária foi realizada naquele dia. Como um rastreador de hábitos de papel simples.
A pilha tecnológica era óbvia para mim: react, django, postgres, nginx, uwsgi.
Layout da IU inicial
Decidi começar pela interface do usuário e instalei nodejs.org/en/download/package-manager , github.com/facebook/create-react-app e , em seguida, criei um projeto:
npx create-react-app easytrack
E comecei o layout. Desde o início, não consegui pensar em nada mais fácil do que codificar uma lista de objetos de lógica de negócios diretamente no programa e exibi-los como uma lista na tag ul. Esses objetos são: o grupo de tópicos, o item rastreado, os registros de rastreamento reais de um item específico em um dia específico.
Na primeira página, eu tinha grupos temáticos, e clicando em qualquer um deles abri uma lista de itens que podem ser rastreados.
Também inventei outra página, que continha uma tabela simples com estatísticas dos últimos dias.
Desenvolva um back-end
Nesta fase, era necessário um back-end. É necessário salvar objetos no banco de dados, gerenciar usuários e diferenciar direitos. Eu já tive que usar o Django para meus próprios projetos (não levado à sua conclusão lógica, é claro), mas havia uma dificuldade - tive que usar o Django Rest Framework, com o qual nunca havia lidado. Agradecimentos ao livro Building Django 2.0 Web-applications [1]. Eu li de capa a capa, exceto pelo último capítulo, onde eles criaram APIs no DRF, eu folheei com meus olhos. No decorrer da história, vou recorrer a ela mais de uma vez.
Para lugar nenhum, abri a documentação do www.django-rest-framework.org e comecei a fumar, e também abri o livro mencionado.
Instalei e ativei o ambiente virtual, instalei o Django e criei um projeto django na raiz do projeto:
virtualenv venv
. ./venv/bin/activate
pip install django
django createproject config
Vou renomear a pasta principal para django, para que pelo nome tudo sobre seu conteúdo seja imediatamente claro. Dentro dele estará um módulo python chamado config, que também é muito conveniente. Código de front-end embrulhado na pasta react. Foi assim que se desenvolveu a estrutura geral de pastas, que foi preservada até hoje ( veja o Github ).
Na raiz do projeto foi criado o aplicativo principal:
django createapp core
Criei classes de modelos de lógica de negócios exatamente no mesmo formato em que os codifiquei na frente, serializadores e visualizações ( link para commit no Github ).
Não nos preocupamos com o banco de dados e usamos o SQLite padrão. Por meio do painel de administração, carreguei algumas amostras de dados de teste que codifiquei anteriormente na frente. Estamos tentando nos conectar ao frontend. python3 manage.py runserver em uma guia, yarn start em outra e dirigiu.
O servidor de desenvolvimento React roda na porta 3000 e o Django roda na porta 8000. Nada é mais fácil do que escrever uma solicitação fetch ('http: // localhost: 8000 / ...') na frente. Mas não funcionou assim por causa da origem do cors - uma proteção especial que impede qualquer site de fazer solicitações automáticas a qualquer servidor. Portanto, sem pensar duas vezes, eu o construí no backenddjango-cors-headers ), configurei - funcionou. Só então pensei em adicionar uma seção de proxy ao package.json e apontar para o backend, então fetch ('/ api / v1 / ...') começou a funcionar normalmente e nenhuma configuração extra foi necessária.
No início, foi terrivelmente ingênuo, porque fiz solicitações assíncronas no construtor - tudo funcionou para mim e ok. Só mais tarde aprendi sobre os métodos de ciclo de vida, onde você pode e onde não deve fazer esse tipo de trabalho. Agora que os elementos foram exibidos, novos elementos podem ser criados.
Implementar gerenciamento de usuários e separação de direitos
Nesse estágio, a única coisa que faltava era a separação dos direitos dos elementos de dados: todos eles foram criados em nome de um usuário desbloqueado anônimo. Eu precisava me integrar a ele de alguma forma, sem quebrar o ecossistema django.
Para começar, codifiquei o login / senha no front-end e formei o cabeçalho de autorização com o valor 'Basic' + base64.encode (username + ":" + senha). Então pensei em gerar uma string no formato base64 e salvá-la no cliente ao inserir um nome de usuário / senha. Mas havia grandes dúvidas sobre esta decisão em termos de segurança, queria tentar algo diferente.
Eu vasculhei a Internet por um curto período de tempo e aprendi sobre a tecnologia JWT e o módulo django-rest-framework-simplejwque forneceu classes de autenticação para DRF e visualizações para obter um par de tokens e para atualizar um token de acesso.
Do lado do front-end, foi suficiente salvar alguns tokens em localStorage e passar o cabeçalho Authorization com o valor "Bearer access-token". Finalmente, coloquei as páginas de login e fechei todo o acesso de usuários não autorizados ao site usando classes de permissão ( link para o commit do Github ). Na frente, se não houvesse token de atualização, redirecionava para a página de login ( link para o commit do Github ).
Depois, possibilitei o cadastro no site, criei uma view no backend, fiz o layout de uma página, configurei o envio de requisições. No futuro, meu sonho era escrever a ativação de conta por e-mail.
Refatorar, implementar funções básicas ausentes, CI
Naquele momento, surgiu um aplicativo minimamente utilizável e eu queria receber feedback. Mostrei o aplicativo para minha esposa e pedi para usá-lo sem uma única solicitação minha. O registro foi bem sucedido, mas nem tudo saiu como eu pensava. Então percebi que as pastas de assunto não deveriam estar em primeiro plano, mas deveriam ser uma ferramenta auxiliar, e também precisamos adicionar dicas de que estamos criando um conjunto de botões para que possamos clicar neles uma vez por dia. Ela esperava que fosse como um rastreador de hábitos de papel comum com uma planilha onde você precisa pintar sobre as células. Quando percebi isso, comecei a refatorar. Além disso, havia algo a refatorar. Examinei a estrutura do módulo quase do zero.
Neste ponto, decidi adicionar beleza, estilos de CSS e layout responsivo. Nisto não sou particularmente forte e confiei em frameworks CSS. A escolha recaiu sobre Bulma , com base no número de estrelas, downloads de npmjs.com , apesar de eu não querer fazer Bootstrap. No mínimo, enfrentei essa tarefa.
Paralelamente, melhorei as funções de back-end. Fiz um CRUD completo. O sonho de confirmar o cadastro pelo correio também se tornou realidade. Eu descobri as funções de enviar cartas, ganhei a capacidade de depurar tudo através de um servidor de e-mail de depuração.
python -m smtpd -n -c DebuggingServer localhost:1025
Para encenar, criei uma conta de lixo eletrônico no Google e consegui configurar o envio de cartas pelo correio do Google.
Quanto à cobertura de teste para o backend, tudo funcionou muito bem por si só, mas para o frontend tudo está completamente lento até agora. Mas eu não me desespero, de repente então tudo se ajustará.
A próxima etapa foi configurar o CI, iniciei GithubActions para executar os testes, usei os construtores de configuração para executá-lo, ajustei um pouco e é isso.
Gerar configurações para o ambiente de produção
Após um curto período de tempo colocando o código e pequenos detalhes da lógica em ordem, tive que começar a formar a configuração de produção. Para isso, fui inspirado pelo mesmo livro [1]. Eu divido os arquivos de configuração do django, python-dependencies em 3 partes ( link para o commit do Github ):
- comum - tudo que você precisa para qualquer ambiente
- dev —
- prod —
, .
uwsgi, nginx , dockerfile, .
[1] «1 — 1 », , , . phusion/baseimage, Ubuntu, .
, , postgres, . ( Github).
production-
, [1], AWS, . , - . , , , , . Free Tier, , , ? .
, AWS - , . , . , ECS.
Elastic Container Service
Eu vi que o construtor Github Actions permite que você crie uma configuração para uma tarefa de implantação contínua de contêiner no AWS ECS. Digamos que eu comecei a me aprofundar neste serviço e percebi que no console local preciso criar um cluster, criar uma definição de tarefa e descrever o contêiner, tendo previamente salvo sua imagem em outro serviço AWS ECR, que é Dockerhub por função. O console oferece 2 tipos de clusters: Fargate e EC2. A primeira tecnologia é totalmente sem servidor, o que significa que apenas iniciamos o contêiner e o tempo de execução cuida de tudo. Os contêineres em um cluster do segundo tipo são executados em sua própria instância de máquina virtual na nuvem. Não querendo mergulhar nisso por muito tempo, criei um cluster baseado no Fargate. Mas descobri que não podia passar valores secretos para o contêiner,por causa disso, a tarefa estava caindo constantemente.
Enquanto eu tentava colocar o contêiner em um estado de funcionamento, o cluster estava funcionando por várias horas e foi adicionado dinheiro à minha guia com o pagamento dos serviços. A tecnologia em si acabou sendo paga e não se aplica ao nível gratuito. Eu paguei o cluster e decidi lidar com o pagamento um pouco mais tarde. Eu li na documentação que você não precisa pagar a mais para usar o ECS em cima do EC2, exceto para usar recursos do EC2, mas o EC2 é coberto pelo nível gratuito e decidi tentar este caminho.
Suporte AWS
No final, alguém mentiu para mim e cobraram mais algum dinheiro por essa configuração. Um total de $ 0,32, embora um pouco, mas ainda uma pena. Aí escrevi em apoio, disse que tinha dificuldades com o setup e o tempo todo pensei que me encaixava no nível gratuito, mas nada funcionou para mim, e o dinheiro foi retirado. Eu pedi ajuda. Em resposta ao meu telefonema, eles responderam alegremente e deram um voucher de $ 1, que cobria todas as despesas inesperadas. Agradável.
Como resultado, eu tive que esquecer esse serviço de contêiner e master EC2 em sua forma mais pura.
Elastic Computing Cloud
EC2 — . Free Tier 750 . , , - , .
[1] docker-machine, . , EC2. docker .
, dockre-machine create… EC2. docker-compose up -d . 80 . , «Public DNS» , .
Relational Database Service
AWS RDS. . , ( postgres) , Free Tier, . , , .
Simple Email Service
Também tive que enfrentar o fato de que as cartas não foram enviadas. O fato é que todos os serviços de e-mail proíbem IPs que correspondem às instâncias do EC2 para combater o spam. Era imperativo usar o SES. Outro serviço AWS.
Eu também configurei, indiquei as caixas de correio das quais vou enviar cartas, está tudo bem. No entanto, nem tudo está tão feliz até agora. Novas contas estão no modo sandbox por padrão, o que não permite o envio de emails para caixas de correio não confirmadas. Tive que confirmar caixas para meus testadores beta.
Registre um domínio e configure um certificado para acesso https
Para testar totalmente o aplicativo, foi necessário configurar uma conexão https, e isso acabou sendo impossível sem registrar um domínio. Eu não queria colocar endereços de e-mail, senhas e tokens em risco transferindo-os por uma conexão não segura. Para este caso, pesquisei toda a Internet. Alguns registradores não serviam, porque era caro, mas em algum lugar era muito caro, além disso, muitos tinham apenas análises terríveis. Enquanto eu olhava, a rede de publicidade Yandex entendeu o que eu queria e imediatamente me ofereceu uma empresa onde eu pudesse registrar um domínio por 39 rublos. Houve mais comentários sobre este serviço, então criei uma conta, escolhi um domínio grátis e registrei para mim.
Em seguida, para acessar minha instância EC2 usando este domínio, criei uma zona de hospedagem no serviço AWS Route 53, registrei as configurações DNS e reescrevi os registros NS na conta pessoal do serviço onde o domínio foi registrado para os da Amazon.
Usei o serviço Let's Encrypt para criar o certificado. Parei nesta configuração: o nginx local faz um proxy_pass para o endereço do contêiner, o contêiner gira e fica acessível pela porta 8080. Não foi difícil usar o utilitário certbot console, gerar um certificado e configurar automaticamente o https. Por fim, permita o acesso à máquina virtual na porta 443.
O desenvolvimento do projeto chegou à sua conclusão lógica
, . , , SES , . , . , , , , , , , , . , , . :
- , , . .
- -
- ,
- , -
— , , . React , AWS, , , .
Mas a principal constatação é que quem está no campo não é um guerreiro. Trabalhei neste projeto por mais de dois meses, muitas horas no meu tempo livre ... E sabe o que mais? Nunca costurei tão mal. Torna-se perceptível que quanto mais você envelhece, menos vontade de aprender algo "assim", menos vontade de trabalhar muito em algumas coisas que são "simplesmente interessantes". Mas, ao mesmo tempo, você percebe que há mais oportunidades disponíveis de fazer algo para o bem, para o benefício. Você começa a apreciar os esforços concentrados, o trabalho em equipe, bem como o relaxamento, o tempo gasto com pessoas próximas.