Como decidimos otimizar as imagens - e no processo, redesenhamos o site, o painel de administração e a abordagem da interface

Boris Goryachev, diretor técnico da Meduza, relata.



Nosso produto principal - o site - está constantemente adquirindo novas funções, mas por isso está se tornando cada vez mais difícil e pesado. Portanto, nosso departamento técnico está ocupado de vez em quando para torná-lo mais fácil e rápido.







Um dos principais elementos que afetam a velocidade de carregamento de quase qualquer site, especialmente um site de mídia, são as imagens. Há muitas fotos na Meduza, e essa é uma forma valiosa de os editores contarem histórias. Os requisitos do nosso serviço de fotos podem ser formulados da seguinte forma:



  • a imagem deve ser enviada ao CMS (nós o chamamos de "Monitor") o mais rápido possível
  • a imagem deve permanecer bonita e ter uma boa aparência em todas as plataformas
  • o leitor não precisa esperar que esta imagem carregue




Primeira abordagem



Quando lançamos em 2014, o processo de trabalhar com imagens carregadas no Monitor era assim: o arquivo era carregado em um aplicativo Rails, usando Paperclip e Imagemagick, era limpo de metadados, compactado com a qualidade selecionada (para JPEG era em torno de 75) e cortado em três tamanhos: pequeno para telefones, maior para tablets e telefones com telas grandes e muito grande para computadores. Os arquivos fatiados foram colocados no armazenamento em nuvem da AWS junto com o original. Eles foram fornecidos (e são fornecidos) não diretamente da AWS, mas por meio de nosso CDN, que os armazena em cache em seus servidores de borda.



A API que gera JSON para o site e aplicativos, então, além de atributos simples como cabeçalhos de materiais, também deu um grande pedaço de código HTML, que foi inserido na parte "conteúdo" do material e foi ponderado com estilos CSS. E a API em si era então a mesma para todos os clientes: o site, aplicativos e serviços de suporte como RSS e pesquisa.







Ficou imediatamente claro para nós que essa abordagem não resistiria ao teste do tempo, mas era necessário lançar rapidamente, testar um grande número de hipóteses, experimentar, sobreviver. Nós conscientemente - pelo menos acreditamos nisso - escolhemos "muletas", e não a beleza do código e das soluções. O tempo passou, nosso público e nosso produto cresceram. E junto com isso, o apetite dos editores cresceu. Os editores queriam cada vez mais técnicas e "truques" em seus materiais. Ao mesmo tempo, é claro, o design também mudou.



O departamento técnico teve que ajustar os estilos das fotos, os métodos de exibi-las, os tamanhos - eles mudaram junto com as mudanças no design e novos elementos no site. Adicionamos e apoiamos cada vez mais soluções estranhas.



Aqui está um deles




Com o tempo, o Monitor enfureceu a todos que o encontravam cada vez mais: a equipe editorial sofria de bugs, porque a correção desses bugs demorava muito, os desenvolvedores ficavam furiosos e as limitações da arquitetura inventada não agradavam aos patrões - não podíamos desenvolver o produto rapidamente.



Começamos a reformular o Monitor. Reescrevemos a parte principal do CMS responsável por trabalhar nos materiais por cerca de um ano, sendo regularmente distraídos por bugs na versão antiga. Em seguida, um meme interno apareceu em "Meduza": "Será no novo Monitor." Foi assim que respondemos à maioria dos pedidos dos editores, embora, é claro, tenhamos feito algumas coisas simultaneamente no antigo e no novo CMS: uma versão ruim para agora e uma versão boa para depois.



Em breve escreverei um post separado em nosso blog com detalhes sobre a alteração do "Monitor" .



Reiniciar



Depois de reiniciar e reconstruir todo o Meduza, a API permaneceu o mesmo no formato, mas não foi mais gerada pelo próprio CMS, mas foi processada por um serviço separado. E finalmente decidimos dividir a API em várias - para clientes diferentes.



Decidimos começar com aplicativos móveis. Naquela época, eles já tinham dúvidas sobre design, UX e velocidade de trabalho, então limpamos os aplicativos e tornamos a API do jeito que nossos desenvolvedores iOS e Android queriam.



Antes da separação da API, mostrávamos parte do conteúdo dos materiais através do WebView, para que não pudéssemos mostrar algo exclusivamente no aplicativo ou exclusivamente no site - tudo era exibido em todos os lugares. Agora temos a oportunidade de gerenciar o conteúdo de forma mais flexível: enviar apenas o necessário para aplicativos móveis, mostrar elementos pesados ​​de uma maneira diferente (como inserções de vídeo no YouTube) e, finalmente, fazer Lazy Load, que permite que você carregue gradualmente elementos pesados ​​no material - fotos e incorporações.



Separados os aplicativos, nos concentramos no site. Nesse ponto, já estava decidido que não faríamos alterações no código do site existente, mas escreveríamos tudo do zero (sim, nos envolvemos em um projeto que durou mais de um ano novamente). Ao mesmo tempo, nosso diretor técnico foi substituído e, em meu novo cargo, tive que auditar os projetos, decidir o que poderia ser encerrado e coordenar com meus superiores. Apesar de todas as dificuldades, a equipe decidiu concluir o novo site. Mas antes disso, decidi que precisávamos de outro projeto.



Foi assim que surgiu o kit UI da Medusa.



Para ser flexível na entrega de conteúdo, ele precisava estar em uma forma que fosse mais adequada para transformações. Os limites semânticos das unidades de conteúdo - imagens, parágrafos de texto, títulos - devem ser bem alinhados. Uma parte do conteúdo não deve ser muito simples ou muito complexa. Se for complexo, provavelmente terá mais de um significado. Se for muito simples, muito provavelmente, ao usá-lo, terá que ser ponderado com complicadores lógicos, e quando você precisar reutilizar tal unidade, você terá que copiá-lo em diferentes partes do código do projeto.



Veja os jogos da Medusa, por exemplo .... Eles permitem que você conte um grande número de histórias de uma forma lúdica. Podem ser feitos especificamente para a agenda ou a pedido do anunciante. Ou o jogo pode ser feito com base na chamada mecânica - formatos que são usados ​​repetidamente (por exemplo, são testes).



Jogos no Meduza: Como Projetamos, Fazemos e Reutilizamos

O código desses jogos não está no código do site. Cada um deles é criado como um microsserviço separado, incorporado ao site por meio de um iframe e se comunicando com o próprio site por meio de postMessage. E o site realmente não se importa com o que mostrar no lugar onde o jogo estará. Além disso, o jogo em si deve ser visualmente inseparável do site: a tipografia e os elementos de interface devem ser os mesmos.







Quando começamos a fazer jogos, copiamos estilos, botões e outras coisas e, claro, era rápido e parecia bom por fora, mas era terrível por dentro.



A equipe decidiu que isso deveria ser alterado. Pausamos a correspondência do site e começamos a fazer nosso próprio UI-kit - uma biblioteca que incluía todos os elementos e estilos repetidos. Procuramos não perder uma perspectiva longa: o site, os jogos e a mecânica - tudo tinha que começar a usar a mesma biblioteca.



Todos os projetos do Meduza na web são escritos em React, e o UI-kit é um módulo npm que agora se conecta a quase tudo que desenvolvemos. E o desenvolvedor, quando precisa renderizar algo, escreve algo assim: renderizar blocos.







O que isso faz?



  1. O desenvolvedor front-end não pensa exatamente em como renderizar algo.
  2. Tudo já foi revisado pelo departamento de design.
  3. : UI-kit, , , . , «», .
  4. — - UI-kit ( ) .


UI-kit



Existem dois grupos de componentes: conteúdo e front-end. Os últimos são componentes React muito simples, como botões e ícones.











Os componentes de conteúdo são um pouco mais complexos, mas ainda assim componentes React muito simples com estilos que representam uma única unidade de conteúdo. Por exemplo, é assim que um componente de parágrafo se parece:







Um componente que "captura" blocos simples







E este é um componente que renderiza uma imagem: a







API da qual o site obtém dados, dentro de cada material contém uma matriz de componentes que são eventualmente "renderizados" através do UI-kit ... Com os jogos, tudo funciona da mesma forma, eles apenas buscam seus dados nas versões da API.



Hooray, nós reiniciamos!



Abaixo está um gráfico que mostra o tempo médio de carregamento da página. Este é um indicador muito impreciso - todas as páginas em todos os dispositivos são levadas em consideração - mas até dá uma ideia da tendência.







O gráfico mostra como a velocidade do site mudou ao longo de toda a existência da Meduza. Quando lançamos um site muito simples em 2014, foi muito rápido. Mas quando começamos a adicionar novos recursos, a velocidade de download caiu.



E aqui está o mesmo cronograma, mas nos últimos dois anos. Mostra como o tempo de carregamento da página diminuiu depois que o site foi reiniciado.







Então chegou a hora das fotos.



Imagens



O esquema de trabalhar com imagens era então. A imagem veio por meio da API, onde tinha um endereço como /images/attachments/.../random.jpg . O próprio arquivo foi servido do armazenamento em nuvem da AWS por meio de nosso CDN.







Formulamos os requisitos para o novo sistema da seguinte forma:



  • a solução deve nos permitir mudar rapidamente o tamanho e a qualidade das imagens renderizadas
  • não precisa ser caro
  • deve ser capaz de lidar com muito tráfego


O esquema pelo qual estávamos lutando acabou assim. O back-end geraria uma URL que seria capturada pelo cliente - navegador ou aplicativo. O URL conteria informações sobre qual imagem é necessária, em que qualidade e qual tamanho ela deveria ter.



Se a imagem neste URL já estiver no servidor Edge, ela será imediatamente servida ao cliente. Caso contrário, o servidor Edge "baterá" no próximo servidor, que já teria passado a solicitação ao serviço. Este serviço, tendo recebido o URL da imagem, iria decodificá-la e determinar o endereço da imagem original e a lista de operações sobre ela. Depois disso, o serviço serviria a imagem transformada para que ela fosse armazenada no CDN e servida mediante solicitação.







Meduza já tem soluções semelhantes. Por exemplo, também fazemos imagens para fragmentos de nossos materiais e jogos em redes sociais - neste serviço, fazemos capturas de tela de páginas HTML por meio do Headless Chrome.



O novo serviço deveria ser capaz de trabalhar com imagens, aplicar efeitos simples, ser rápido e resiliente. Já que adoramos escrever tudo nós mesmos, foi planejado originalmente escrever tal serviço na linguagem Elixir. Mas ninguém na equipe teve tempo suficiente, e certamente ninguém teve o desejo de mergulhar no maravilhoso mundo do jpg, png e gif.



Ainda precisávamos encontrar uma biblioteca que comprimiria as imagens. Imagemagick, com que já tínhamos experiência, não era a solução mais rápida, mas pelo menos sabíamos prepará-la. Todo o resto era novo e haveria muito o que verificar.



Também precisávamos de suporte para o formato de imagem webp.



O tempo passou, preparamo-nos mentalmente para mergulhar neste projeto. Mas então um de nossos programadores leu sobre a biblioteca imgproxy, que os caras do Evil Martians fizeram o upload para o Open Source . De acordo com a descrição, foi um hit perfeito: Go, Libvps, uma imagem Docker pronta, configurando via Env. No mesmo dia, implantamos a biblioteca em nossos laptops e pedimos ao nosso DevOps para brincar com ela também. Sua tarefa era aumentar o serviço e tentar eliminá-lo - para que pudéssemos entender as cargas que ele suportará em nossos servidores. Durante esse tempo, a equipe de back-end continuou a brincar com o projeto em seus computadores: escrevemos scripts Ruby e dominamos as funções disponíveis.







Quando DevOps retornou com o veredicto de que a biblioteca poderia ser usada na produção, coletamos um grande número de imagens que foram passadas por imgproxy - estávamos principalmente interessados ​​em webp - e pegamos suas diretivas de fotos. Os colaboradores do departamento técnico não podem decidir por si próprios se esta qualidade nos é adequada ou não. Os editores de fotos nos enviaram seus comentários, ajustamos algo, nos certificamos de que as imagens não pesavam muito e fomos escrever o código de back-end.



Aqui tudo acabou sendo muito simples: como na versão da API do site, as imagens já estavam separadas por componentes de todo o resto, simplesmente estendemos seu JSON e adicionamos endereços adicionais em diferentes tamanhos e formatos.











O atualizado imediatamente entrou em produção, já que não mudamos nada, apenas adicionamos - os caras do frontend podiam desenvolver funções todas na mesma versão da API. Eles expandiram o componente de imagem em termos de funções, adicionaram conjuntos de imagens para diferentes tamanhos e uma "muleta" especial para o Safari. Mudamos a tabela de tamanhos algumas vezes e verificamos o resultado pelos olhos da redação - para isso demos a ela a versão atual do site e uma duplicata com novas imagens para revisão.



Quando os comentários pararam de chegar, finalmente implementamos, descartamos o cache e colocamos em produção.



Resultado



A essência de nossas mudanças pode ser resumida da seguinte forma: mudamos o lugar de tomada de decisão sobre qual imagem dar de que forma para o lugar onde o contexto é melhor levado em consideração e a implementação e o suporte são mais fáceis de implementar.



Hoje em dia, quase todas as fotos que você vê na Meduza são fruto do trabalho da imgproxy, e em cada caso elas têm tamanhos diferentes e às vezes qualidade diferente. Isso é determinado pelo contexto - se o conteúdo é aberto na web, aplicativo móvel ou AMP - conhecido pelo serviço de API que gera as respostas.



All Articles