Como criei um serviço de controle de qualidade a partir de mesas e paus

Olá Habr! Freqüentemente, ao pensar em lançar um piloto, os gerentes começam a complicar a situação, a criar roteiros e a aguardar o MVP dos desenvolvedores, em vez de tomar e testar a ideia por conta própria. Segundo o corte, quero compartilhar a história da criação de um serviço de controle de qualidade com base nos formulários do Google, VK e dezenas de linhas de código, nas quais nenhum desenvolvedor ficou ferido, apenas 1 profissional de marketing.



Isenção de responsabilidade : neste artigo, estou aguardando exemplos de código que lhe causarão perguntas, dúvidas, talvez até lágrimas e cegueira sangrenta. Como justificativa, há apenas uma coisa a ser dita - esse código funcionou como o Papa Carlo e cumpriu sua missão 100%, e alguns scripts ainda funcionam.

Primeira classificação da Pizzaria Dodo


Um dos principais princípios de nossa empresa - o que não pode ser medido, não existe . Existe pizza, o que significa que você precisa avaliar de alguma forma sua qualidade.

Tudo começou em 2013. Naquela época, havia 7 pizzarias na rede. Então, em Dodo, eles decidiram lançar um projeto para controlar a qualidade e os padrões dos produtos - uma classificação de pizzarias abertas a todos os parceiros.

Ele parecia assim.



Os dados foram retirados de ligações de clientes, análises no social. redes e um pouco do Dodo IS (nosso sistema de informação).

Uma vantagem óbvia na época - a classificação começou a levar as pizzarias que gerenciavam a trabalhar com qualidade para ficar no topo.

Second Mystery Shop Pizzarias


Cerca de um ano depois, percebemos que precisávamos avaliar o produto em si e adotamos o famoso modelo - “compradores misteriosos”. Naquele momento, fizemos um grande avanço - o primeiro na Rússia decidiu que nossos clientes seriam os compradores misteriosos.

O surgimento de um grupo fechado VK


Inicialmente, descobrimos como eles trabalham com compradores misteriosos em agências que fornecem esses serviços. Descobriu-se que eles se comunicam por e-mail ou ligam diretamente para oferecer verificação.

Essa opção não nos seduziu imediatamente. Definitivamente não íamos telefonar, porque para nós demorou muito tempo, mas para um cliente era doloroso e parecido com o spam. O correio era usado para correspondência em massa, mas logo foram abandonados.

Nós criamos:

  1. Para comunicação com agentes secretos e coordenação de verificações, eles usaram a página usual em VK.
  2. Para coletar reportagens fotográficas, eles formaram um grupo na VK com uma parede aberta.
  3. E para pesquisas de serviço, escolhemos os formulários do Google. O que? Convenientemente, você não precisa cortar um serviço separado e ele é bem exibido no celular.
  4. Todas as instruções estavam no Google Docs.

Tudo está no joelho. Tudo é como deveria ser para uma startup.


Foto de um cliente misterioso. Sim, eles mediram a largura com uma régua, cortaram a borda da pizza para mostrar o cozimento e a qualidade da massa.

Mais exemplos de reportagens fotográficas de 2015 estão aqui.





A classificação mudava constantemente, novos critérios de avaliação foram adicionados. Por exemplo, são 131 pontos para avaliar a pizzaria Abakan-1.



Todo o processo foi que todas as violações nos pontos foram anotadas manualmente, sem automação. E tudo isso foi feito por um funcionário.

A mágica das planilhas do Google


Em 2016, aprendemos (amadurecemos) que a humanidade há muito tempo inventa outras funções além de = SUM. E o que pode ser feito usando scripts e funções de importação de dados entre tabelas ... Compilação do Direct CRM.

Por exemplo, avaliar cada pizzaria na tabela era uma folha, e nela critérios e pontuações de avaliação. 1 pizzaria = 1 folha. Quanto mais pizzarias, mais lençóis. Toda semana um novo sinal. Pressionando o botão mágico, a folha de modelo na tabela foi expandida em 120 folhas. Wah, que bom!



Esse estágio de automação “Dodo Controlling” levou cerca de seis meses. Mudamos passo a passo: aprendemos algo novo - implementado, aprendemos algo novo - introduzido novamente.

Limitação como motor do progresso


Desde o início, conversamos com compradores misteriosos em nome de uma conta pessoal na VK. E então chegou o dia em que nos deparamos com problemas insolúveis de páginas pessoais:

  • há um limite de 10.000 amigos;
  • Há um limite para o envio de mensagens: às vezes não podíamos enviar mensagens, porque a VK nos bloqueou com a frase “você enviou muitas mensagens, venha amanhã”.

Normalmente, o VK bloqueava o envio de mensagens por volta das 16:00. Foi um happy hour quando a equipe pôde descansar.

Gradualmente, encontramos quase todas as limitações do VK e quase conseguimos parar de amar este site. Mas um milagre aconteceu, e o VK deu aos grupos a oportunidade de conectar widgets de mensagens, bots de bate-papo e outras vantagens.

De fato, essa possibilidade era anterior a dezembro de 2016, mas com uma restrição crítica para nós: o grupo poderia responder à mensagem apenas dentro de 10 dias a partir do momento em que a última mensagem fosse enviada pelo cliente. Quando eles removeram essa restrição, a vida de nossa equipe começou a brilhar com novas cores. Desde então, começamos o caminho da automação usando a API VK e as planilhas do Google.

Medo e ódio em um script de usuário


Inicialmente, para se tornar um cliente misterioso, você precisava preencher um formulário, depois se inscrever no grupo, escrever uma palavra-chave e aguardar a resposta. Essa espera pode durar até 48 horas. Foi indecentemente longo e o desejo de realizar verificações após esse registro desapareceu.

Com um novo repositório de conhecimentos, decidimos automatizar o registro.

Tínhamos vários métodos de API, um formulário, várias dezenas de tabelas, uma landing page, um bot em PHP, scripts na tabela que foram escritos pelo mais legal comerciante Dodo e o primeiro CFO do Dodo em uma pessoa, dezenas de modelos de mensagens para diferentes situações. Eu nem sabia que isso era chamado de script de usuário:

  1. O comprador misterioso preencheu um questionário (esta é uma versão desatualizada e agora não funciona).
  2. Os dados do formulário caíram primeiro no banco de dados e depois na tabela. O bot primeiro bateu no banco de dados para verificar os dados sobre o perfil, porque o tempo limite de resposta da placa em dezenas de milhares de linhas era grande e o banco de dados o digeriu facilmente).
  3. Após preencher o questionário no formulário, uma mensagem apareceu na tela: "Obrigado, resta participar do grupo (link) e escreva a palavra de código" Sherlock "".
  4. Em seguida, o comprador misterioso enviou um pedido para ingressar no grupo e escreveu a palavra de código "Sherlock". A palavra foi o gatilho para executar o script de validação:
    - foi enviada uma solicitação ao banco de dados se o agente é adequado para nós por idade;
    - nesse caso, a pessoa foi adicionada aos grupos e, na tabela ao lado do questionário do candidato, foi colocado o status “ok / não ok”;
    - Mais dados foram pintados na cor turquesa e isso foi importante. Então, com meus olhos, era mais fácil entender quem nos convém e com quem podemos falar. O script pintou perfis inadequados em vermelho;
    - Além disso, o comprador secreto foi aceito automaticamente no grupo e uma mensagem foi enviada ao bate-papo com mais etapas e instruções.



Essa é a automação do registro. Agora, todo o procedimento tornou-se quase simples e compreensível.

Além disso, tudo correu como um relógio. Ficou claro que podemos enviar mensagens por meio de tabelas diretamente para o PM para agentes secretos por meio de mensagens em grupo.



E você tinha 46 linhas de código!

function send() { var range = SpreadsheetApp.getActiveSpreadsheet().getActiveRange(); var ss = range.getValues(); var carray = range.offset(0, -2).getValues(); var marray = range.offset(0, 1).getValues(); var iarray = range.offset(0, 0).getValues(); ss.forEach(function (r, i) { var tt = range.getRowIndex(); var add = tt + i; var check = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('L' + add).getValue(); if (check != '') { SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('K' + add).setValue("").setBackground("#ffff00"); return; } var payload = { "message" : marray[i][0], "user_id" : r[0], "access_token" : "    ", "v" : "5.74" }; var options = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload, "muteHttpExceptions" : true, }; var jsonData = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.send", options).getContentText()); if (jsonData['error'] != undefined) { SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('K' + add).setValue("").setBackground("#ff0000"); } Logger.log(jsonData); var log = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log'); var int = log.getRange('A1').getValue(); var d = new Date(); log.getRange('B' + int).setValue(d); log.getRange('C' + int).setValue(r[0] + ""); log.getRange('A1').setValue(int + 1); Utilities.sleep(400); }); } 

Nas tabelas, geramos o texto das mensagens e fizemos correspondências personalizadas usando a página de identificação. Também paramos de copiar e enviar mensagens manualmente. Nos horários de pico, poderíamos enviar até 3000 mensagens em 45 minutos usando tabelas. Se o fizéssemos manualmente, eu não escreveria este artigo, mas continuaria a enviar mensagens.

A seguir, dou um exemplo de uma tábua milagrosa. Eu tentei muito criar um UX / UI claro e funcional. Ao clicar no botão vermelho, uma lista de discussão foi lançada com uma proposta para realizar uma verificação secreta.



Mais recursos para automatizar processos infernais


A empresa possui muitos formulários do Google que nos ajudam a coletar algumas métricas de pizzarias continuamente. Cada formulário possui uma lista de pizzarias que precisam ser atualizadas. Existem 53 formulários no total, cada um deles atualizado anteriormente manualmente.

Um pouco cansados ​​desse trabalho, percebemos que esse negócio poderia ser automatizado. Voltei a procurar nosso profissional de marketing, depois de uma ou duas horas tudo estava pronto e apenas 47 linhas de código.

 function myFunction() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getActiveRange(); var forms = range.offset(0, 1).getValues(); var items = range.offset(0, 2).getValues(); var sources = range.offset(0, 3).getValues(); var ranges = range.offset(0, 4).getValues(); forms.forEach(function (r,i) { var form = FormApp.openById(forms[i]); var values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sources[i]).getRange(ranges[i]).getValues(); var arr = []; values.forEach(function (el,ei) { if (el[0] != '') { arr.push(el[0]); } }); var item = form.getItems()[Number(items[i])].asListItem(); item.setChoiceValues(arr); Logger.log(item.getTitle()); }); } function getData() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getSheetByName("    ").getRange("A2:C").getValues(); Logger.log(range); } function onOpen() { var ui = SpreadsheetApp.getUi(); // Or DocumentApp or FormApp. ui.createMenu('Custom Menu') .addItem('Change', 'myFunction') .addToUi(); } function update() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var range = ss.getSheetByName(" ").getRange("A2:A"); range.activate(); myFunction(); } function createTimeDrivenTriggers() { ScriptApp.newTrigger('update').timeBased().everyDays(1).create(); } 

Os formulários são diferentes, com diferentes listas de pizzarias e o local da lista de pizzarias no formulário. Em algum lugar precisamos de estrangeiros, em algum lugar da Rússia.



As colunas B e C informam ao script em qual formulário atualizar e em que local o formulário exibe a lista. E as colunas D e E, de qual planilha e intervalo você precisa obter a lista para atualização.

Em seguida, eles acionaram o script para executar o script uma vez por dia e, assim, foram capazes de derrotar o inferno do processo de atualização de formulários primeiro para o departamento e depois para toda a empresa. Este script ainda funciona.

O caso mais difícil sobre um caracol


Uma vez quisemos receber gravações de áudio das verificações de entrega.

De onde veio a gravação de áudio: compradores misteriosos gravaram a reunião do correio com o cliente como uma mensagem de áudio no VK. Normalmente, são 10 a 15 segundos de gravação de áudio.

Como os conseguimos: eles pegaram as últimas 20 mensagens no endereço VK do comprador misterioso, procuraram a palavra "Ulica" entre eles, depois recuaram uma mensagem e pegaram o link para a gravação de áudio. (Spoiler: não é a melhor palavra, geralmente eles nos escrevem a palavra "Snail").

Já existem mais linhas de código, prepare-se.

 function getLastAudio() { var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); var token = ''; var range = ss.getActiveRange().getValues(); var tt = ss.getActiveRange().getRowIndex(); range.forEach(function (r,i) { var ri = tt + i; var cuid = r[0]; var ci = 0; var payload1 = { "q" : '', 'peer_id' : r[0], "access_token" : token, "v" : "5.73", }; var options1 = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload1, "muteHttpExceptions" : true }; var jsonData = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.search", options1).getContentText()); Logger.log(jsonData); if (jsonData['response']['items'] == undefined) { ss.getRange("B" + ri).setValue(' ').setBackground('#f00'); return; } var cmid = jsonData['response']['items'][0]['id']; var date = new Date((jsonData['response']['items'][0]['date']*1000)); var fdate = Utilities.formatDate(date, "GMT+3", "dd-MM-yyyy HH:mm:ss"); ss.getRange("B" + ri).setValue(fdate); var payload2 = { "user_id" : cuid, "count" : '20', "access_token" : token, "v" : "5.73", }; var options2 = { //   http- "method" : "post", "header" : "Content-type: application/x-www-form-urlencoded", "payload" : payload2, "muteHttpExceptions" : true }; var jsonData2 = JSON.parse(UrlFetchApp.fetch("https://api.vk.com/method/messages.getHistory", options2).getContentText()); Logger.log(jsonData2); jsonData2['response']['items'].forEach(function (r,i) { if (r['id'] == cmid) { ci = i + 1; Logger.log(jsonData2['response']['items'][ci]); if (jsonData2['response']['items'][ci] == undefined) { ss.getRange("C" + ri).setValue(" "); } else { if (jsonData2['response']['items'][ci] != undefined && jsonData2['response']['items'][ci]['attachments'] != undefined && jsonData2['response']['items'][ci]['attachments'][0]['doc'] != undefined && jsonData2['response']['items'][ci]['attachments'][0]['doc']['url'] != undefined) { ss.getRange("C" + ri).setValue(jsonData2['response']['items'][ci]['attachments'][0]['doc']['url']); } else { ss.getRange("C" + ri).setValue(jsonData2['response']['items'][ci]['body']); } } } }); }); } 

As planilhas do Google não são flexíveis, mas eu sou um codificador


Então, tudo estava girando e girando, até que crescemos até 60 mil compradores misteriosos no início de 2018.

Portanto, já enfrentamos restrições de tabela. Então, uma tabela não pode conter mais de 2 milhões de células e usamos 1,6 milhão de células em um dos rótulos de departamento mais ocupados, dos quais 135 mil células tinham todos os tipos de funções da tabela.

Tal back-end. Tudo desacelerou terrivelmente e, quando várias pessoas trabalharam juntas, o prato cedeu "O documento é popular demais, volte mais tarde".

Então ficou claro que eu sou um codificador ruim, o sistema não retém a carga e preciso ser substituído.

E então o verdadeiro desenvolvedor veio ...


Mas esta é uma história completamente diferente e iremos escrever sobre isso mais tarde. Espero que esses exemplos ajudem os gerentes em seus projetos, onde existem muitos processos infernais. Os processos podem e devem ser automatizados, as tabelas e o zapier (também o usamos) podem ajudar e, se houver recursos, não havia soluções domésticas no começo.

Se você tem uma pessoa na empresa que sabe algo sobre scripts, ela é adequada para organizar processos infernais em tablets. Se você quiser aprender algo assim, o Telegram tem um excelente canal para isso, do qual peguei informações sobre funções e scripts.

Bem, masthead para todos os gerentes - conhecer as tabelas todos os dias economiza tempo ao trabalhar com dados e permite que você pense e entenda pelo menos um pouco o que o desenvolvedor faz com os dados e o que você pode fazer com os dados em geral.

Source: https://habr.com/ru/post/pt472856/


All Articles