{"id":36721,"date":"2019-10-31T22:13:20","date_gmt":"2019-10-31T19:13:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/kak-dark-razvertyvaet-kod-za-50-ms\/"},"modified":"2019-10-31T22:13:20","modified_gmt":"2019-10-31T19:13:20","slug":"kak-dark-razvertyvaet-kod-za-50-ms","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","title":{"rendered":"Como o Dark executa c\u00f3digo em 50 ms","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Como o Dark executa c\u00f3digo em 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/c159a36eb52bf488f3a70ea511690366.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Quanto mais r\u00e1pido \u00e9 o processo de desenvolvimento, mais rapidamente se desenvolve a empresa de tecnologia.<\/p>\n<p><\/p>\n<p>Infelizmente, os aplicativos modernos trabalham contra n\u00f3s \u2014 nossos sistemas devem ser atualizados em tempo real, sem atrapalhar ningu\u00e9m e sem causar interrup\u00e7\u00f5es ou paralisa\u00e7\u00f5es. A implanta\u00e7\u00e3o em tais sistemas torna-se uma tarefa complexa e exige pipelines complexos de entrega cont\u00ednua, mesmo em equipes pequenas.<\/p>\n<p><\/p>\n<p>Esses pipelines geralmente t\u00eam um escopo limitado, funcionam lentamente e n\u00e3o s\u00e3o muito confi\u00e1veis. Os desenvolvedores devem cri\u00e1-los manualmente primeiro e depois gerenci\u00e1-los, e as empresas costumam contratar equipes inteiras de DevOps para isso.<\/p>\n<p><\/p>\n<p>A velocidade desses pipelines determina a velocidade de desenvolvimento. Para as melhores equipes, a implanta\u00e7\u00e3o leva de 5 a 10 minutos, mas geralmente tudo demora muito mais, e uma \u00fanica implanta\u00e7\u00e3o pode levar v\u00e1rias horas.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>No Dark, isso leva 50 ms. <em>Cinquenta. Milissegundos.<\/em>. Dark \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">\u00e9 uma solu\u00e7\u00e3o abrangente com uma linguagem de programa\u00e7\u00e3o, um editor e infraestrutura<\/a><\/noindex>, criada especificamente para entrega cont\u00ednua, e todos os aspectos do Dark, incluindo a pr\u00f3pria linguagem, s\u00e3o constru\u00eddos com a vis\u00e3o de implanta\u00e7\u00e3o instant\u00e2nea e segura.<\/p>\n<p><\/p>\n<h3 id=\"pochemu-konveyery-nepreryvnoy-postavki-takie-medlennye\">Por que os pipelines de entrega cont\u00ednua s\u00e3o t\u00e3o lentos?<\/h3>\n<p><\/p>\n<p>Suponha que temos um aplicativo web em Python e j\u00e1 criamos um pipeline de entrega cont\u00ednua not\u00e1vel e moderno. Para um desenvolvedor que est\u00e1 diariamente ocupado com este projeto, implantar uma pequena altera\u00e7\u00e3o parecer\u00e1 mais ou menos assim:<\/p>\n<p><\/p>\n<h3 id=\"vnesenie-izmeneniy\">Fazendo as altera\u00e7\u00f5es.<\/h3>\n<p><\/p>\n<ul>\n<li>Criando uma nova branch no git.<\/li>\n<li>Fazendo altera\u00e7\u00f5es por tr\u00e1s do interruptor de recursos.<\/li>\n<li>Testes unit\u00e1rios para verificar as altera\u00e7\u00f5es com e sem o interruptor de recursos.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"pul-rekvest\">Pull request.<\/h3>\n<p><\/p>\n<ul>\n<li>Commit das altera\u00e7\u00f5es.<\/li>\n<li>Enviando altera\u00e7\u00f5es para o reposit\u00f3rio remoto no GitHub.<\/li>\n<li>Pull request.<\/li>\n<li>A constru\u00e7\u00e3o do CI \u00e9 executada automaticamente em segundo plano.<\/li>\n<li>Revis\u00e3o de c\u00f3digo.<\/li>\n<li>Mais algumas revis\u00f5es, se necess\u00e1rio.<\/li>\n<li>Mesclando as altera\u00e7\u00f5es com o master do git.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"ci-vypolnyaetsya-na-mastere\">O CI \u00e9 executado no master.<\/h3>\n<p><\/p>\n<ul>\n<li>Instalando depend\u00eancias de frontend via npm.<\/li>\n<li>Construindo e otimizando recursos HTML+CSS+JS.<\/li>\n<li>Executando testes unit\u00e1rios e funcionais no frontend.<\/li>\n<li>Instalando depend\u00eancias de Python do PyPI.<\/li>\n<li>Executando testes unit\u00e1rios e funcionais no backend.<\/li>\n<li>Testando integra\u00e7\u00e3o em ambas as extremidades.<\/li>\n<li>Enviando recursos de frontend para o CDN.<\/li>\n<li>Construindo o container para o programa Python.<\/li>\n<li>Envio do cont\u00eainer para o registro<\/li>\n<li>Atualiza\u00e7\u00e3o do manifesto do Kubernetes<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"zamena-starogo-koda-novym\">Substitui\u00e7\u00e3o do c\u00f3digo antigo pelo novo<\/h3>\n<p><\/p>\n<ul>\n<li>O Kubernetes inicia v\u00e1rias inst\u00e2ncias do novo cont\u00eainer<\/li>\n<li>O Kubernetes aguarda para que as inst\u00e2ncias fiquem operacionais<\/li>\n<li>O Kubernetes adiciona as inst\u00e2ncias ao balanceador de carga HTTP<\/li>\n<li>O Kubernetes espera at\u00e9 que as inst\u00e2ncias antigas deixem de ser utilizadas<\/li>\n<li>O Kubernetes interrompe as inst\u00e2ncias antigas<\/li>\n<li>O Kubernetes repete essas opera\u00e7\u00f5es at\u00e9 que todas as inst\u00e2ncias antigas sejam substitu\u00eddas<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"vklyuchenie-novogo-pereklyuchatelya-funkcii\">Ativa\u00e7\u00e3o do novo recurso<\/h3>\n<p><\/p>\n<ul>\n<li>O novo c\u00f3digo \u00e9 ativado apenas para si mesmo, para garantir que tudo esteja funcionando corretamente<\/li>\n<li>O novo c\u00f3digo \u00e9 ativado para 10% dos usu\u00e1rios, monitorando m\u00e9tricas operacionais e de neg\u00f3cios<\/li>\n<li>O novo c\u00f3digo \u00e9 ativado para 50% dos usu\u00e1rios, monitorando m\u00e9tricas operacionais e de neg\u00f3cios<\/li>\n<li>O novo c\u00f3digo \u00e9 ativado para 100% dos usu\u00e1rios, monitorando m\u00e9tricas operacionais e de neg\u00f3cios<\/li>\n<li>Finalmente, voc\u00ea repete todo o procedimento para remover o c\u00f3digo antigo e o recurso<\/li>\n<\/ul>\n<p><\/p>\n<p>O processo depende das ferramentas, da linguagem e do uso de arquiteturas orientadas a servi\u00e7os, mas, em geral, se parece com isso. N\u00e3o mencionei implanta\u00e7\u00f5es com migra\u00e7\u00f5es de banco de dados, pois isso requer um planejamento cuidadoso, mas abaixo explicarei como a Dark lida com isso.<\/p>\n<p><\/p>\n<p>H\u00e1 muitos componentes, e muitos deles podem facilmente causar lentid\u00e3o, falhas, competi\u00e7\u00e3o tempor\u00e1ria ou derrubar o sistema operacional.<\/p>\n<p><\/p>\n<p>E como esses pipelines quase sempre s\u00e3o criados para casos espec\u00edficos, \u00e9 dif\u00edcil confiar neles. Muitas vezes, h\u00e1 dias em que o c\u00f3digo n\u00e3o pode ser implantado porque h\u00e1 problemas no Dockerfile, uma das dezenas de servi\u00e7os falhou ou o especialista necess\u00e1rio est\u00e1 de f\u00e9rias.<\/p>\n<p><\/p>\n<p>Pior ainda, muitos desses passos n\u00e3o fazem nada \u00fatil. Eles eram necess\u00e1rios antes, quando implant\u00e1vamos o c\u00f3digo diretamente para os usu\u00e1rios, mas agora temos recursos para o novo c\u00f3digo, e esses processos foram separados. Como resultado, a etapa que implanta o c\u00f3digo (o antigo sendo substitu\u00eddo pelo novo) agora se tornou apenas um risco desnecess\u00e1rio.<\/p>\n<p><\/p>\n<p>Claro, este \u00e9 um pipeline muito bem pensado. A equipe que o criou n\u00e3o hesitou em investir tempo e dinheiro para uma r\u00e1pida implementa\u00e7\u00e3o. Normalmente, os pipelines de implanta\u00e7\u00e3o s\u00e3o muito mais lentos e menos confi\u00e1veis.<\/p>\n<p><\/p>\n<h3 id=\"realizaciya-nepreryvnoy-postavki-v-dark\">Implementa\u00e7\u00e3o de entrega cont\u00ednua na Dark<\/h3>\n<p><\/p>\n<p>A entrega cont\u00ednua \u00e9 t\u00e3o importante para a Dark que, desde o in\u00edcio, miramos em um tempo de resposta inferior a um segundo. Revisamos todas as etapas do pipeline para eliminar o que era excessivo e refinamos o restante. Veja como removemos etapas.<\/p>\n<p><\/p>\n<blockquote><p>Jesse Frazelle (<noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jessie Frazelle<\/a><\/noindex>) criou a nova palavra deployless (sem necessidade de implanta\u00e7\u00e3o) na confer\u00eancia Future of Software Development em Reykjavik.<\/p><\/blockquote>\n<p>Decidimos imediatamente que a Dark seria baseada no conceito de 'deployless' (obrigado <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/jessfraz\">Jesse Frazelle<\/a><\/noindex> pelo neologismo). Deployless significa que qualquer c\u00f3digo \u00e9 implantado instantaneamente e est\u00e1 pronto para uso em produ\u00e7\u00e3o. Claro, n\u00e3o ignoramos c\u00f3digo com erros ou incompleto (descreverei os princ\u00edpios de seguran\u00e7a abaixo).<\/p>\n<p><\/p>\n<p>Durante a demonstra\u00e7\u00e3o da Dark, muitas vezes nos perguntavam como conseguimos acelerar tanto a implanta\u00e7\u00e3o. Uma pergunta estranha. As pessoas provavelmente pensam que desenvolvemos alguma supertecnologia que compara c\u00f3digo, compila, empacota em cont\u00eaineres, inicia m\u00e1quinas virtuais, inicia cont\u00eaineres a frio e tudo mais em 50 ms. Isso \u00e9 improv\u00e1vel. Mas criamos um mecanismo de implanta\u00e7\u00e3o especial que n\u00e3o precisa de tudo isso.<\/p>\n<p><\/p>\n<p>A Dark executa interpretadores na nuvem. Suponha que voc\u00ea esteja escrevendo c\u00f3digo em uma fun\u00e7\u00e3o ou manipulador HTTP ou de eventos. Enviamos a diferen\u00e7a para a \u00e1rvore de sintaxe abstrata (a implementa\u00e7\u00e3o do c\u00f3digo que nossos editores e servidores usam internamente) para nossos servidores e, em seguida, executamos esse c\u00f3digo quando as solicita\u00e7\u00f5es chegam. Assim, a implanta\u00e7\u00e3o parece apenas uma simples entrada de banco de dados \u2014 instant\u00e2nea e elementar. A implanta\u00e7\u00e3o ocorre t\u00e3o rapidamente porque envolve o m\u00ednimo poss\u00edvel.<\/p>\n<p><\/p>\n<p>No futuro, planejamos transformar a Dark em um compilador de infraestrutura que criar\u00e1 e executar\u00e1 a infraestrutura ideal para alta performance e confiabilidade de aplicativos. A implanta\u00e7\u00e3o instant\u00e2nea, \u00e9 claro, n\u00e3o ir\u00e1 a lugar algum.<\/p>\n<p><\/p>\n<h2 id=\"bezopasnoe-razvertyvanie\">Implanta\u00e7\u00e3o segura<\/h2>\n<p><\/p>\n<h3 id=\"strukturirovannyy-redaktor\">Editor estruturado<\/h3>\n<p><\/p>\n<p>O c\u00f3digo na Dark \u00e9 escrito no editor Dark. O editor estruturado n\u00e3o permite erros sint\u00e1ticos. Essencialmente, na Dark n\u00e3o h\u00e1 mesmo um analisador. Enquanto voc\u00ea digita, trabalhamos diretamente com a \u00e1rvore de sintaxe abstrata (AST), assim como <noindex><a rel=\"nofollow\" href=\"http:\/\/danmidwood.com\/content\/2014\/11\/21\/animated-paredit.html\">Paredit<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/ravichugh.github.io\/sketch-n-sketch\/\">Sketch-n-Sketch<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/gregoor.github.io\/tofu\/\">Tofu<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.facebook.com\/notes\/kent-beck\/prune-a-code-editor-that-is-not-a-text-editor\/1012061842160013\/\">Prune<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jetbrains.com\/mps\/\">MPS<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Qualquer c\u00f3digo incompleto na Dark tem uma sem\u00e2ntica de execu\u00e7\u00e3o v\u00e1lida, semelhante a <noindex><a rel=\"nofollow\" href=\"https:\/\/hazel.org\/\">typed holes em Hazel<\/a><\/noindex>. Por exemplo, se voc\u00ea alterar a chamada de uma fun\u00e7\u00e3o, n\u00f3s armazenamos a fun\u00e7\u00e3o antiga at\u00e9 que a nova se torne utiliz\u00e1vel.<\/p>\n<p><\/p>\n<p>Cada programa em Dark tem seu pr\u00f3prio prop\u00f3sito, portanto, um c\u00f3digo n\u00e3o finalizado n\u00e3o impede o funcionamento do c\u00f3digo finalizado.<\/p>\n<p><\/p>\n<h3 id=\"rezhimy-redaktirovaniya\">Modos de Edi\u00e7\u00e3o<\/h3>\n<p><\/p>\n<p>Voc\u00ea escreve c\u00f3digo em Dark em duas situa\u00e7\u00f5es. Primeira: voc\u00ea est\u00e1 escrevendo um c\u00f3digo novo e \u00e9 o \u00fanico usu\u00e1rio. Por exemplo, ele est\u00e1 no REPL e outros usu\u00e1rios nunca ter\u00e3o acesso a ele, ou \u00e9 uma nova rota HTTP \u00e0 qual voc\u00ea n\u00e3o se refere em nenhum lugar. Aqui voc\u00ea pode trabalhar sem nenhuma precau\u00e7\u00e3o, e \u00e9 assim que voc\u00ea est\u00e1 operando no ambiente de desenvolvimento.<\/p>\n<p><\/p>\n<p>Segunda situa\u00e7\u00e3o: o c\u00f3digo j\u00e1 est\u00e1 em uso. Se h\u00e1 tr\u00e1fego passando pelo c\u00f3digo (fun\u00e7\u00f5es, manipuladores de eventos, bancos de dados, etc.), precisa-se ter cuidado. Para isso, bloqueamos todo o c\u00f3digo em uso e exigimos o uso de ferramentas mais estruturadas para sua edi\u00e7\u00e3o. Sobre as ferramentas estruturadas, falarei a seguir: interruptores de fun\u00e7\u00f5es para manipuladores HTTP e de eventos, uma plataforma poderosa de migra\u00e7\u00e3o para bancos de dados e um novo m\u00e9todo de controle de vers\u00e3o para fun\u00e7\u00f5es e tipos.<\/p>\n<p><\/p>\n<h3 id=\"pereklyuchateli-funkciy\">Interruptores de Fun\u00e7\u00f5es<\/h3>\n<p><\/p>\n<p>Uma das maneiras <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">de eliminar complexidade desnecess\u00e1ria<\/a><\/noindex> em Dark \u00e9 resolver v\u00e1rios problemas com uma \u00fanica solu\u00e7\u00e3o. Interruptores de fun\u00e7\u00f5es realizam diversas tarefas: substitui\u00e7\u00e3o do ambiente local de desenvolvimento, ramifica\u00e7\u00f5es Git, implanta\u00e7\u00e3o de c\u00f3digo e, claro, o tradicional lan\u00e7amento lento e controlado de novo c\u00f3digo.<\/p>\n<p><\/p>\n<p>A cria\u00e7\u00e3o e a implanta\u00e7\u00e3o de um interruptor de fun\u00e7\u00e3o s\u00e3o realizadas em nosso editor em uma \u00fanica opera\u00e7\u00e3o. Ele cria um espa\u00e7o vazio para o novo c\u00f3digo e fornece controles de acesso ao c\u00f3digo antigo e novo, al\u00e9m de bot\u00f5es e comandos para uma transi\u00e7\u00e3o gradual para o novo c\u00f3digo ou sua exclus\u00e3o.<\/p>\n<p><\/p>\n<p>Interruptores de fun\u00e7\u00f5es s\u00e3o integrados \u00e0 linguagem Dark, e mesmo interruptores n\u00e3o finalizados realizam sua tarefa \u2014 se a condi\u00e7\u00e3o no interruptor n\u00e3o for atendida, o c\u00f3digo antigo bloqueado ser\u00e1 executado.<\/p>\n<p><\/p>\n<h3 id=\"sreda-razrabotki\">Ambiente de desenvolvimento<\/h3>\n<p><\/p>\n<p>Os switches de funcionalidades substituem o ambiente de desenvolvimento local. Hoje, as equipes t\u00eam dificuldade em garantir que todos estejam usando as mesmas vers\u00f5es de ferramentas e bibliotecas (ferramentas de formata\u00e7\u00e3o de c\u00f3digo, linters, gerenciadores de pacotes, compiladores, pr\u00e9-processadores, ferramentas de teste, etc.). Com o Dark, n\u00e3o \u00e9 necess\u00e1rio instalar depend\u00eancias localmente, gerenciar uma instala\u00e7\u00e3o local do Docker ou tomar outras medidas para garantir pelo menos uma certa equival\u00eancia entre o desenvolvimento e a produ\u00e7\u00e3o. <noindex><a rel=\"nofollow\" href=\"https:\/\/thenewstack.io\/honeycombs-charity-majors-go-ahead-test-in-production\/\">Considerando que tal equival\u00eancia \u00e9 imposs\u00edvel<\/a><\/noindex>, n\u00e3o vamos nem mesmo fingir que estamos buscando isso.<\/p>\n<p><\/p>\n<p>Em vez de criar um ambiente local clonado, os switches no Dark criam uma nova sandbox em produ\u00e7\u00e3o que substitui o ambiente de desenvolvimento. No futuro, tamb\u00e9m planejamos criar sandboxes para outras partes do aplicativo (como clones instant\u00e2neos do banco de dados), embora isso ainda n\u00e3o pare\u00e7a t\u00e3o importante.<\/p>\n<p><\/p>\n<h3 id=\"vetki-i-razvertyvaniya\">Branches e implanta\u00e7\u00f5es<\/h3>\n<p><\/p>\n<p>Atualmente, existem v\u00e1rias maneiras de introduzir novo c\u00f3digo nos sistemas: branches git, etapas de implanta\u00e7\u00e3o e switches de funcionalidades. Eles resolvem um problema em diferentes partes do fluxo de trabalho: o git \u2014 nas etapas antes da implanta\u00e7\u00e3o, a implanta\u00e7\u00e3o \u2014 no momento da transi\u00e7\u00e3o do c\u00f3digo antigo para o novo, e os switches de funcionalidades \u2014 para lan\u00e7amentos controlados do novo c\u00f3digo.<\/p>\n<p><\/p>\n<p>A maneira mais eficaz \u00e9 atrav\u00e9s dos switches de funcionalidades (que tamb\u00e9m s\u00e3o a mais simples de entender e usar). Com eles, \u00e9 poss\u00edvel abrir m\u00e3o dos outros dois m\u00e9todos. Especialmente \u00e9 \u00fatil eliminar a etapa de implanta\u00e7\u00e3o \u2014 se j\u00e1 estamos usando switches de funcionalidades para ativar o c\u00f3digo, ent\u00e3o o passo de transi\u00e7\u00e3o dos servidores para o novo c\u00f3digo apenas cria riscos desnecess\u00e1rios.<\/p>\n<p><\/p>\n<p>Git \u00e9 dif\u00edcil de usar, especialmente para iniciantes, e isso limita bastante, mas ele tem branches convenientes. N\u00f3s suavizamos muitas das desvantagens do git. O Dark \u00e9 editado em tempo real e fornece a capacidade de colabora\u00e7\u00e3o no estilo do Google Docs, para que n\u00e3o seja necess\u00e1rio enviar c\u00f3digo e para que o rebase e merge sejam feitos com menos frequ\u00eancia.<\/p>\n<p><\/p>\n<p>Os switches de fun\u00e7\u00f5es s\u00e3o a base para uma implementa\u00e7\u00e3o segura. Juntamente com as implementa\u00e7\u00f5es instant\u00e2neas, eles permitem que voc\u00ea teste rapidamente conceitos em pequenos fragmentos com baixo risco, em vez de aplicar uma grande mudan\u00e7a que pode derrubar o sistema.<\/p>\n<p><\/p>\n<h3 id=\"versionirovanie\">Versionamento<\/h3>\n<p><\/p>\n<p>Para alterar fun\u00e7\u00f5es e tipos, usamos versionamento. Se voc\u00ea deseja modificar uma fun\u00e7\u00e3o, o Dark cria uma nova vers\u00e3o dessa fun\u00e7\u00e3o. Depois, voc\u00ea pode chamar essa vers\u00e3o com um switch no manipulador HTTP ou de eventos. (Se a fun\u00e7\u00e3o estiver profundamente na \u00e1rvore de chamadas, uma nova vers\u00e3o de cada fun\u00e7\u00e3o ser\u00e1 criada ao longo do caminho. Pode parecer excessivo, mas as fun\u00e7\u00f5es n\u00e3o interferem se voc\u00ea n\u00e3o as utilizar, ent\u00e3o voc\u00ea nem vai notar.)<\/p>\n<p><\/p>\n<p>Pelos mesmos motivos, tamb\u00e9m versionamos tipos. J\u00e1 falamos sobre nosso sistema de tipos em detalhes. <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">no post anterior<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Gra\u00e7as ao versionamento de fun\u00e7\u00f5es e tipos, voc\u00ea pode fazer altera\u00e7\u00f5es no aplicativo gradualmente. \u00c9 poss\u00edvel verificar se cada manipulador individual funciona com a nova vers\u00e3o, sem precisar fazer todas as mudan\u00e7as no aplicativo de uma s\u00f3 vez (mas temos ferramentas para fazer isso rapidamente, se voc\u00ea desejar).<\/p>\n<p><\/p>\n<p>Isso \u00e9 muito mais seguro do que um deploy completo de tudo de uma vez, como acontece atualmente.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-paketov-i-standartnaya-biblioteka\">Novas vers\u00f5es de pacotes e da biblioteca padr\u00e3o.<\/h3>\n<p><\/p>\n<p>Quando voc\u00ea atualiza um pacote no Dark, n\u00e3o substitu\u00edmos imediatamente o uso de cada fun\u00e7\u00e3o ou tipo em toda a base de c\u00f3digo. Isso n\u00e3o \u00e9 seguro. O c\u00f3digo continua usando a mesma vers\u00e3o que estava usando, e voc\u00ea atualiza o uso de fun\u00e7\u00f5es e tipos para a nova vers\u00e3o para cada caso espec\u00edfico utilizando switches.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/rh\/t3\/4w\/rht34wyibolrgracbz88tnqqhg0.png\"><img decoding=\"async\" alt=\"Como o Dark executa c\u00f3digo em 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/54fdb566b4bcbc10e06e51c47a3820f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Captura de tela de parte do processo autom\u00e1tico no Dark, mostrando duas vers\u00f5es da fun\u00e7\u00e3o Dict::get. Dict::get_v0 retornava o tipo Any (do qual estamos nos afastando), enquanto Dict::get_v1 retorna o tipo Option.<\/em><\/p>\n<p><\/p>\n<p>Frequentemente, fornecemos uma nova fun\u00e7\u00e3o na biblioteca padr\u00e3o e exclu\u00edmos as vers\u00f5es antigas. Usu\u00e1rios com vers\u00f5es antigas em seu c\u00f3digo ainda ter\u00e3o acesso a elas, mas novos usu\u00e1rios n\u00e3o conseguir\u00e3o obt\u00ea-las. Pretendemos fornecer ferramentas para migrar usu\u00e1rios de vers\u00f5es antigas para novas em um \u00fanico passo, novamente utilizando switches de fun\u00e7\u00f5es.<\/p>\n<p><\/p>\n<p>A Dark tamb\u00e9m oferece uma oportunidade \u00fanica: como executamos seu c\u00f3digo, podemos testar novas vers\u00f5es, comparando as sa\u00eddas para novas e antigas solicita\u00e7\u00f5es, para inform\u00e1-lo sobre as mudan\u00e7as. Assim, a atualiza\u00e7\u00e3o de pacotes, que muitas vezes \u00e9 feita \u00e0s cegas (ou requer testes rigorosos por raz\u00f5es de seguran\u00e7a), apresenta muito menos riscos e pode ocorrer automaticamente.<\/p>\n<p><\/p>\n<h3 id=\"novye-versii-dark\">Novas vers\u00f5es do Dark<\/h3>\n<p><\/p>\n<p>A transi\u00e7\u00e3o do Python 2 para o Python 3 se estendeu por uma d\u00e9cada e ainda \u00e9 um problema. Como estamos desenvolvendo o Dark para entrega cont\u00ednua, \u00e9 necess\u00e1rio levar em considera\u00e7\u00e3o essas mudan\u00e7as de linguagem.<\/p>\n<p><\/p>\n<p>Quando fazemos pequenas altera\u00e7\u00f5es na linguagem, criamos uma nova vers\u00e3o do Dark. O c\u00f3digo antigo permanece na vers\u00e3o antiga do Dark, enquanto o novo c\u00f3digo \u00e9 utilizado na nova vers\u00e3o. Para mudar para a nova vers\u00e3o do Dark, pode-se usar switches ou vers\u00f5es de funcionalidades.<\/p>\n<p><\/p>\n<p>Isso \u00e9 especialmente \u00fatil, considerando que o Dark \u00e9 bastante recente. Muitas mudan\u00e7as na linguagem ou na biblioteca podem acabar sendo frustrantes. A versiona\u00e7\u00e3o gradual da linguagem nos permite fazer atualiza\u00e7\u00f5es menores, ou seja, podemos n\u00e3o ter pressa e adiar muitas decis\u00f5es de linguagem at\u00e9 que tenhamos mais usu\u00e1rios, e portanto mais informa\u00e7\u00f5es.<\/p>\n<p><\/p>\n<h3 id=\"migracii-baz-dannyh\">Migra\u00e7\u00f5es de banco de dados<\/h3>\n<p><\/p>\n<p>Para uma migra\u00e7\u00e3o de banco de dados segura, existe uma <noindex><a rel=\"nofollow\" href=\"http:\/\/www.brunton-spall.co.uk\/post\/2014\/05\/06\/database-migrations-done-right\/\">f\u00f3rmula padr\u00e3o<\/a><\/noindex>:<\/p>\n<p><\/p>\n<ul>\n<li>Reescrever o c\u00f3digo para suportar os novos e antigos formatos<\/li>\n<li>Converter todos os dados para o novo formato<\/li>\n<li>Remover o antigo acesso aos dados<\/li>\n<\/ul>\n<p><\/p>\n<p>Como resultado, a migra\u00e7\u00e3o de banco de dados se torna demorada e consome muitos recursos. E acumulamos esquemas obsoletos, j\u00e1 que at\u00e9 tarefas simples, como corrigir o nome de uma tabela ou coluna, n\u00e3o valem o esfor\u00e7o empregado.<\/p>\n<p><\/p>\n<p>O Dark possui uma plataforma de migra\u00e7\u00e3o de banco de dados eficaz, que (esperamos) simplificar\u00e1 tanto o processo que voc\u00ea deixar\u00e1 de t\u00ea-lo como um medo. Todos os reposit\u00f3rios de dados no Dark (reposit\u00f3rios de pares \"chave-valor\" ou tabelas hash persistentes) t\u00eam tipo. Para transferir um reposit\u00f3rio de dados, voc\u00ea simplesmente atribui a ele um novo tipo e uma fun\u00e7\u00e3o de revers\u00e3o e aplica\u00e7\u00e3o para converter valores entre os dois tipos.<\/p>\n<p><\/p>\n<p>O acesso aos reposit\u00f3rios de dados no Dark \u00e9 feito atrav\u00e9s de nomes de vari\u00e1veis versionados. Por exemplo, o reposit\u00f3rio de dados Users ser\u00e1 inicialmente chamado de Users-v0. Quando uma nova vers\u00e3o com um tipo diferente \u00e9 criada, o nome muda para Users-v1. Se os dados forem salvos via Users-v0 e voc\u00ea acess\u00e1-los atrav\u00e9s de Users-v1, aplica-se a fun\u00e7\u00e3o de aplica\u00e7\u00e3o. Se os dados forem salvos via Users-v1 e voc\u00ea acess\u00e1-los atrav\u00e9s de Users-v0, aplica-se a fun\u00e7\u00e3o de revers\u00e3o.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/ui\/sl\/wd\/uislwdrfrvact0d1ts5icnk-4ka.png\"><img decoding=\"async\" alt=\"Como o Dark executa c\u00f3digo em 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/35743ba246f327ca9e8b71f0069a3800.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>A tela de migra\u00e7\u00e3o da base de dados com os nomes dos campos da antiga base de dados, express\u00f5es de aplica\u00e7\u00e3o e revers\u00e3o e instru\u00e7\u00f5es para habilitar a migra\u00e7\u00e3o.<\/em><\/p>\n<p><\/p>\n<p>Use switches de features para direcionar as chamadas de Users-v0 para a vers\u00e3o Users-v1. Isso pode ser feito um manipulador HTTP por vez, para reduzir riscos, e os switches funcionam para usu\u00e1rios individuais, para que voc\u00ea possa verificar se tudo est\u00e1 funcionando como esperado. Quando n\u00e3o restar nenhum usu\u00e1rio de Users-v0, o Dark converter\u00e1 todos os dados restantes em segundo plano do antigo formato para o novo. Voc\u00ea nem perceber\u00e1.<\/p>\n<p><\/p>\n<h3 id=\"testirovanie\">Testes<\/h3>\n<p><\/p>\n<p>Dark \u00e9 um <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/real-problems-with-functional-languages-efe668c5264a\">linguagem de programa\u00e7\u00e3o funcional com tipagem est\u00e1tica<\/a><\/noindex> e valores imut\u00e1veis, portanto, a superf\u00edcie de teste \u00e9 significativamente menor em compara\u00e7\u00e3o com linguagens orientadas a objetos com tipagem din\u00e2mica. Mas ainda assim, os testes s\u00e3o necess\u00e1rios.<br \/>\nNo Dark, o editor executa automaticamente testes modulares em segundo plano para o c\u00f3digo edit\u00e1vel e, por padr\u00e3o, executa esses testes para todos os switches de features. No futuro, queremos usar tipagem est\u00e1tica para executar fuzzing de c\u00f3digo automaticamente para encontrar bugs.<\/p>\n<p><\/p>\n<p>Al\u00e9m disso, o Dark executa sua infraestrutura em produ\u00e7\u00e3o, abrindo novas oportunidades. Autom\u00e1ticamente salvamos as requisi\u00e7\u00f5es HTTP na infraestrutura do Dark (por enquanto, salvamos todas as requisi\u00e7\u00f5es, mas depois queremos mudar para amostragens). Testamos novo c\u00f3digo com base nelas e realizamos testes modulares, e, se desejar, voc\u00ea pode facilmente transformar requisi\u00e7\u00f5es interessantes em testes modulares.<\/p>\n<p><\/p>\n<h3 id=\"ot-chego-my-izbavilis\">Do que nos livramos<\/h3>\n<p><\/p>\n<p>Como n\u00e3o temos implanta\u00e7\u00f5es, mas sim switches de features, cerca de 60% do pipeline de implanta\u00e7\u00e3o fica de fora. N\u00e3o precisamos de branches git ou pull requests, construir recursos de backend e containers, enviar recursos e containers para registros ou etapas de implanta\u00e7\u00e3o no Kubernetes.<\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/gc\/9e\/g-\/gc9eg-szouq0dtrxxr8jd6c6dyo.jpeg\"><img decoding=\"async\" alt=\"Como o Dark executa c\u00f3digo em 50 ms\" src=\"\/wp-content\/uploads\/2019\/08\/d584b13a1f91e9eef1e2e40c25e90052.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<em>Compara\u00e7\u00e3o entre o pipeline padr\u00e3o de entrega cont\u00ednua (\u00e0 esquerda) e a entrega cont\u00ednua Dark (\u00e0 direita). No Dark, a entrega consiste em 6 etapas e um ciclo, enquanto a vers\u00e3o tradicional inclui 35 etapas e 3 ciclos.<\/em><\/p>\n<p><\/p>\n<p>No Dark, h\u00e1 apenas 6 etapas e 1 ciclo no processo de implanta\u00e7\u00e3o (etapas que se repetem v\u00e1rias vezes), enquanto o pipeline moderno de entrega cont\u00ednua consiste em 35 etapas e 3 ciclos. No Dark, os testes s\u00e3o executados automaticamente, e voc\u00ea nem percebe; as depend\u00eancias s\u00e3o instaladas automaticamente; nada relacionado ao git ou Github \u00e9 mais necess\u00e1rio; n\u00e3o \u00e9 necess\u00e1rio compilar, testar e enviar cont\u00eaineres Docker; a implanta\u00e7\u00e3o no Kubernetes n\u00e3o \u00e9 mais necess\u00e1ria.<\/p>\n<p><\/p>\n<p>Mesmo os passos restantes no Dark se tornaram mais simples. Como os switches de fun\u00e7\u00e3o podem ser gerenciados com uma \u00fanica a\u00e7\u00e3o, n\u00e3o \u00e9 necess\u00e1rio passar novamente por todo o pipeline de implanta\u00e7\u00e3o para remover c\u00f3digo antigo.<\/p>\n<p><\/p>\n<p>Fizemos o poss\u00edvel para simplificar a entrega de c\u00f3digo, reduzindo o tempo e os riscos da entrega cont\u00ednua. Al\u00e9m disso, simplificamos significativamente a atualiza\u00e7\u00e3o de pacotes, migra\u00e7\u00f5es de bancos de dados, testes, gerenciamento de vers\u00f5es, instala\u00e7\u00e3o de depend\u00eancias, igualdade entre o ambiente de desenvolvimento e produ\u00e7\u00e3o e atualiza\u00e7\u00f5es r\u00e1pidas e seguras das vers\u00f5es da linguagem.<\/p>\n<p><\/p>\n<p>Estou respondendo perguntas sobre isso em <noindex><a rel=\"nofollow\" href=\"https:\/\/news.ycombinator.com\/item?id=20394166\">HackerNews<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Para saber mais sobre o dispositivo Dark, leia a <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/darklang\/the-design-of-dark-59f5d38e52d2\">artigo sobre Dark<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/darklang?source=post_page---------------------------\">siga-nos no Twitter<\/a><\/noindex> (ou em <noindex><a rel=\"nofollow\" href=\"https:\/\/twitter.com\/paulbiggar?source=post_page---------------------------\">meu<\/a><\/noindex>) ou <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/subscribe?source=post_page---------------------------\">inscreva-se para a vers\u00e3o beta e receba notifica\u00e7\u00f5es sobre os pr\u00f3ximos posts<\/a><\/noindex>. Se voc\u00ea for ao StrangeLoop em setembro, <noindex><a rel=\"nofollow\" href=\"https:\/\/darklang.com\/launch\">venha nos ver no lan\u00e7amento<\/a><\/noindex>.<\/p>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/southbridge\/blog\/462027\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0440\u043e\u0442\u0438\u0432 \u043d\u0430\u0441 \u2014 \u043d\u0430\u0448\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0438\u043a\u043e\u043c\u0443 \u043d\u0435 \u043c\u0435\u0448\u0430\u0442\u044c \u0438 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u0440\u043e\u0441\u0442\u043e\u044f\u043c \u0438 \u043f\u0435\u0440\u0435\u0440\u044b\u0432\u0430\u043c. \u0420\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u043f\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u0436\u0435 \u0432 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445. [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":27506,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-36721","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0430\u043a Dark \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0437\u0430 50 \u043c\u0441 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:13:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:13:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Como o Dark implanta c\u00f3digo em 50 ms | ProHoster","description":"Quanto mais r\u00e1pido o processo de desenvolvimento, mais r\u00e1pido.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0430\u043a Dark \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0437\u0430 50 \u043c\u0441 | ProHoster","og:description":"\u0427\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0435\u043c \u0431\u044b\u0441\u0442\u0440\u0435\u0435.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/kak-dark-razvertyvaet-kod-za-50-ms","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:13:20+00:00","article:modified_time":"2019-10-31T19:13:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"36721","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 04:34:22","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:40:22","updated":"2026-01-22 04:34:22","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/36721","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=36721"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/36721\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/27506"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=36721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=36721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=36721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}